plan(S1-S4): seção de conteúdos na home de campanha — artigos, YouTube, Instagram + compartilhar WhatsApp
Some checks failed
Agent PR Ready + auto-merge / ready-automerge (pull_request) Has been skipped
CI (PR) / scope (pull_request) Successful in 45s
CI (PR) / docs-guards (pull_request) Successful in 10s
CI (PR) / lint (pull_request) Successful in 1m3s
CI (PR) / plans-only-closes (pull_request) Successful in 8s
CI (PR) / typecheck (pull_request) Has been skipped
CI (PR) / knip (pull_request) Has been skipped
CI (PR) / cycles (pull_request) Has been skipped
CI (PR) / unit (pull_request) Has been skipped
CI (PR) / format (pull_request) Failing after 1m16s
Main merge flips claimed issues to done + in-prod / issue-done (pull_request) Successful in 20s
Promote plan-issue Related on main merge / plan-issue-ready (pull_request) Successful in 15s
Agent pool supervisor / tick (pull_request) Successful in 48s
CI (PR) / int (pull_request) Has been skipped
CI (PR) / build (pull_request) Has been skipped
CI (PR) / e2e (1) (pull_request) Has been skipped
CI (PR) / e2e (2) (pull_request) Has been skipped
CI (PR) / checks (pull_request) Failing after 1s
Some checks failed
Agent PR Ready + auto-merge / ready-automerge (pull_request) Has been skipped
CI (PR) / scope (pull_request) Successful in 45s
CI (PR) / docs-guards (pull_request) Successful in 10s
CI (PR) / lint (pull_request) Successful in 1m3s
CI (PR) / plans-only-closes (pull_request) Successful in 8s
CI (PR) / typecheck (pull_request) Has been skipped
CI (PR) / knip (pull_request) Has been skipped
CI (PR) / cycles (pull_request) Has been skipped
CI (PR) / unit (pull_request) Has been skipped
CI (PR) / format (pull_request) Failing after 1m16s
Main merge flips claimed issues to done + in-prod / issue-done (pull_request) Successful in 20s
Promote plan-issue Related on main merge / plan-issue-ready (pull_request) Successful in 15s
Agent pool supervisor / tick (pull_request) Successful in 48s
CI (PR) / int (pull_request) Has been skipped
CI (PR) / build (pull_request) Has been skipped
CI (PR) / e2e (1) (pull_request) Has been skipped
CI (PR) / e2e (2) (pull_request) Has been skipped
CI (PR) / checks (pull_request) Failing after 1s
This commit is contained in:
parent
e03ba1f83b
commit
70a7ea8e33
9 changed files with 649 additions and 0 deletions
85
docs/plans/compartilhar-conteudos-home-whatsapp.md
Normal file
85
docs/plans/compartilhar-conteudos-home-whatsapp.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# Compartilhar conteúdos da home no WhatsApp (S4)
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-17
|
||||
Issue: #19
|
||||
Priority: P2
|
||||
Model: composer-2.5
|
||||
Impeccable: B — botão discreto de compartilhar por card de conteúdo (não compete com o CTA)
|
||||
Rascunho UI: docs/plans/secao-conteudos-home-ui-draft.html + PNG embutido abaixo
|
||||
Appetite: ~0,5–1 dia eng; botão por card + wa.me com mensagem pré-configurada + copiar link
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
Depois que a seção de conteúdos da home estiver funcional (S1+S2+S3), cada card de conteúdo vira compartilhável no WhatsApp — o canal nº 1 de compartilhamento no Brasil. O visitante manda o artigo/vídeo/post para alguém com uma mensagem pronta (título + link), sem sair da home. É a fatia de viralidade do board: conteúdo circulando de volta para a campanha na reta final.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** visitante (eleitor, liderança, simpatizante) no meio de funil que achou um conteúdo bom e quer mandar para o grupo/família.
|
||||
- **Job principal:** repassar um conteúdo específico da home para alguém no WhatsApp com um clique, com texto pronto.
|
||||
- **Fluxo desejado:** vê o card → toca no botão de compartilhar (ícone discreto no canto do card) → opção "Compartilhar no WhatsApp" (abre `wa.me` com mensagem pré-configurada contendo título + link do conteúdo) e/ou "Copiar link" → cola onde quiser.
|
||||
- **Anti-goals de produto:** o botão de compartilhar NUNCA compete com o CTA primário da página (botão discreto, não é o foco do card); não é compartilhamento por seção inteira (v1 é por card); sem WhatsApp Business API (é `wa.me` do próprio remetente).
|
||||
|
||||
### Esboço de fluxo (B)
|
||||
|
||||
```text
|
||||
[card de conteúdo] → [botão compartilhar (ícone)] → [menu: WhatsApp / Copiar link]
|
||||
→ [wa.me com mensagem "Olha isso do Solla: <título> — <link>"] → [remetente envia pelo próprio WhatsApp]
|
||||
```
|
||||
|
||||
### Rascunho UI (B)
|
||||
|
||||

|
||||
|
||||
Fonte iterável: [`secao-conteudos-home-ui-draft.html`](secao-conteudos-home-ui-draft.html) (cena `compartilhar`).
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Todo card de conteúdo da seção (Artigo/YouTube/Instagram) tem um botão discreto de compartilhar (canto do card, sem competir com o CTA primário da página).
|
||||
- Ação principal: abre `wa.me` com mensagem pré-configurada **por fonte** (decisão do cliente): artigo → "Olha isso do Solla: {título} — {link}" · vídeo → "Olha esse vídeo do Solla: {título} — {link}" · post IG → "Olha esse post do Solla: {título} — {link}". Link: artigo → página canônica do artigo; YT/IG → URL da plataforma. Nova aba com `noopener`.
|
||||
- Ação secundária: "Copiar link" (navegador/clipboard) com feedback de "copiado".
|
||||
- O botão é acessível (aria-label, alvo de toque ≥44px no mobile) e não muda o layout do card. No mobile, o botão vive no card único do carrossel (1 conteúdo por tela — decisão do cliente); no desktop, no canto de cada card do bento.
|
||||
- Sem migration/schema/Consent — o fluxo é montagem de URL no cliente, sem escrita no servidor.
|
||||
- Mensagem padrão honesta (ex.: "Olha isso do Solla: {título} — {link}") — sem texto enganoso.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não — só a URL compartilhada. (Se a assessoria quiser medir circulação, UTM por card é um item futuro separado.)
|
||||
- **Decisões desbloqueadas:** o visitante decide compartilhar; nenhum dado é coletado por este fluxo.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** componente client pequeno no card de conteúdo da seção S1/S2/S3 (`src/components/`), reusando `buildWhatsAppUrl` (`src/utilities/phone.ts`) e o padrão de copiar link já existente (ex.: `ShareNucleusDialog`/`campaignListShare` — ver `docs/plans/compartilhar-pagina.md` como precedente de wa.me + copiar).
|
||||
- **Precedente a olhar:** `compartilhar-pagina.md` (padrão `wa.me` + copiar link + `noopener`), `src/utilities/phone.ts` (`buildWhatsAppUrl`), plano-site §7.1 ("Compartilhamento por seção" — ideia do cliente).
|
||||
- **Risco de acoplamento:** o botão vive no card generalizado da seção — implementar no ponto único de renderização do card (não em três lugares por plataforma).
|
||||
|
||||
## Dependências
|
||||
|
||||
- **S3** (seção completa: artigos + YouTube + Instagram) — dura (conteúdos funcionais antes de compartilhar).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Compartilhar por outros canais (e-mail, X, threads) — só WhatsApp + copiar link no v1.
|
||||
- UTM por seção/card e medição de circulação (item futuro — ideia §7.1 do plano-site).
|
||||
- Imagem OG por seção/card (geração de card de preview) — item futuro (§7.1).
|
||||
- WhatsApp Business API / disparo em massa (vedado pela Res. TSE 23.610; é `wa.me` do próprio remetente).
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Botão de compartilhar competindo com o CTA.** Se alguém "só completar": dois pesos visuais por card. **Corte:** ícone discreto no canto, sem destaque de cor de marca.
|
||||
- **Compartilhar a seção inteira.** Se alguém "só completar": mensagem gigante com N links. **Corte:** v1 é por card, um link por mensagem.
|
||||
- **Telemetria disfarçada de compartilhar.** Se alguém "só completar": vira rastreador de clique. **Corte:** nada é coletado neste item; UTM fica para item futuro explícito.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Mensagem padrão por fonte?** **Opções:** A) template único "Olha isso do Solla: {título} — {link}" | B) específica por fonte (artigo/vídeo/post). **Recomendação:** B — decisão do cliente nesta sessão. _(decidido — B)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #19
|
||||
- Rascunho UI (gate): `docs/plans/secao-conteudos-home-ui-draft.html` (cena `compartilhar`) + PNG acima
|
||||
- `docs/campanha/plano-site-campanha-2026.md` §7.1 — "Compartilhamento por seção" (ideia do cliente registrada)
|
||||
- `docs/plans/compartilhar-pagina.md` — precedente de wa.me + copiar link no repo
|
||||
- `src/utilities/phone.ts` — `buildWhatsAppUrl`
|
||||
- `docs/plans/secao-conteudos-home-artigos.md` (S1) — estrutura do card onde o botão entra
|
||||
93
docs/plans/secao-conteudos-home-artigos.md
Normal file
93
docs/plans/secao-conteudos-home-artigos.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Seção de conteúdos na home de campanha — Artigos (S1)
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-17
|
||||
Issue: #17
|
||||
Priority: P1
|
||||
Model: composer-2.5
|
||||
Impeccable: B — nova seção na home pública (3ª posição), padrão visual do wireframe já aprovado
|
||||
Rascunho UI: docs/plans/secao-conteudos-home-ui-draft.html + PNGs embutidos abaixo
|
||||
Appetite: ~1 dia eng; seção com cards de artigos reusando o sistema `post` existente
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
A home pública de campanha (jorgesolla1313.com.br) não tem nenhuma zona de conteúdo atualizado: ela é estática entre o hero e o CTA. Na reta final (eleição 04/10), as coisas acontecem rápido e o site precisa mostrar atividade. O wireframe já tem a seção "Acompanhe de perto" (board de conteúdo) aprovada — ela só não foi implementada. Este item é a primeira fatia da seção, com **artigos** do site (a fonte que já existe no Teqo); YouTube e Instagram entram nas fatias seguintes (S2/S3), em série, para a estrutura não divergir.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** visitante da home de campanha (eleitor, liderança, imprensa) — celular na maioria dos casos, chegou pelo WhatsApp/redes, no meio de funil.
|
||||
- **Job principal:** ver que a campanha está viva agora (prova de atividade) e ler um conteúdo recente sem sair do clima da página.
|
||||
- **Fluxo desejado:** rola a home → encontra a seção (3ª, logo antes de "Por que essa eleição importa") → vê cards de artigos recentes com badge "Artigo" → clica e vai para a página do artigo (rota canônica do post) → pode voltar e continuar na home.
|
||||
- **Anti-goals de produto:** a seção NÃO vira um feed infinito; NÃO compete com o CTA primário; NÃO mostra conteúdo invisível/oculto (mecanismo `hidden`/`isPostVisible` segue valendo — fail-closed).
|
||||
|
||||
### Esboço de fluxo (B)
|
||||
|
||||
```text
|
||||
[home: hero → prova social] → [SEÇÃO: eyebrow + título + cards artigos] → [clique no card]
|
||||
→ [página do artigo: /[type]/[category]/[slug]] → [voltar à home]
|
||||
```
|
||||
|
||||
### Rascunho UI (B)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Fonte iterável: [`secao-conteudos-home-ui-draft.html`](secao-conteudos-home-ui-draft.html). Nesta fatia S1, o bento mostra só cards "Artigo" (a cena `desktop` já ilustra a posição final com as 3 fontes para referência).
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- A home pública exibe uma nova seção na 3ª posição (entre a prova social e "Por que essa eleição importa"), com eyebrow/título/subtitulo e links de acompanhar conforme o wireframe.
|
||||
- A seção lista artigos recentes visíveis do sistema `post` existente (mesma regra de visibilidade do site: `isPostVisible` fail-closed — conteúdo oculto por tag `hidden` não aparece).
|
||||
- Cada card mostra: badge "Artigo", imagem de capa, título e meta (data/categoria); o card inteiro é um link para a página canônica do artigo (`getPostCanonicalPath`), abrindo na mesma aba.
|
||||
- Layout: bento 1 card grande + 4 pequenos no desktop; **no mobile (~390px) a seção vira um carrossel de 1 conteúdo por tela** (desliza entre os cards, com indicador de página), sem quebrar o fluxo da página.
|
||||
- Se não houver artigos visíveis: a seção inteira é ocultada (nada de zona morta), mantendo Prova → "Por que essa eleição importa" (cena `vazio` do rascunho).
|
||||
- Zero mudança em schema/migration/Consent: artigos leem o `post` collection com os helpers de cache existentes (`getVisiblePosts` / tag `posts`).
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Sim, superfície neste item — mas são **conteúdos** (artigos), não métricas.
|
||||
- **Decisões desbloqueadas:** o visitante decide qual artigo ler (clique); nenhum número novo de campanha é inventado aqui.
|
||||
- **Forma:** *adiada ao plano de implementação* — restrição de produto: meta = data/categoria do post (já exibidas no site), sem contadores inventados.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** `src/app/(frontend)/(home)/page.tsx` (inserir a seção entre prova e problema), novo componente de seção/card em `src/components/`, estilos no bloco `[data-theme='campaign-site']` de `src/app/(frontend)/styles.css` (padrão das seções atuais), leitura via `src/utilities/posts.ts` (`getVisiblePosts`, `getPostCanonicalPath`, `formatPostDate`).
|
||||
- **Precedente a olhar:** wireframe `docs/campanha/wireframe-solla-1313.html` (seção 7, board IG+YT — o design aprovado a adaptar para artigos); seções atuais da home (`campaign-problem`, `campaign-flags`) para o ritmo visual; `src/components/PostCard.tsx` e a rota `/artigos` para o formato de card de post existente.
|
||||
- **Risco de acoplamento:** a seção respeita o mecanismo eleitoral `hidden`/`isPostVisible` (nada de bypass); o cache público é o tag `posts` existente (revalidação já cobre); não duplicar o conceito de "pessoa" nem criar collection nova.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma (primeira fatia). S2 (YouTube) e S3 (Instagram) dependem desta.
|
||||
- Soft: `docs/campanha/plano-site-campanha-2026.md` — decisões de produto do site (board §4.2, posição discutida na §3).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- YouTube e Instagram na seção → S2 e S3 (deste lote).
|
||||
- Compartilhamento WhatsApp → S4 (issue separada).
|
||||
- Player de vídeo inline, lightbox, qualquer embed de rede no load (decisão do plano-site: clique abre na plataforma; sem iframe no carregamento).
|
||||
- Curadoria manual do feed (é automático pelo mais recente), configuração no admin, "pausar feed" (kill switch) → S2/S3.
|
||||
- Redesign da home, alteração de CTA primário, outras seções do wireframe.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Feed infinito / paginação.** Se alguém "só completar": a seção vira uma lista sem fim competindo com o CTA. **Corte neste item:** bento fixo (1 + 4), sem paginação; link "Ver artigos →" aponta para a rota `/artigos` existente.
|
||||
- **Segunda fonte de "artigos" paralela ao `post`.** Se alguém "só completar": duplica o sistema de notícias. **Corte:** só o `post` collection com a visibilidade pública existente.
|
||||
- **Vazio honesto.** A seção oculta quando sem conteúdo — não exibe placeholder de "em breve" queimando o meio de funil.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Posição exata da seção?** **Opções:** A) 3ª seção, logo antes de "Por que essa eleição importa" (recomendação — traz conteúdo atualizado pra cima; decisão do cliente nesta sessão) | B) posição 7 do wireframe (após "Quem é Jorge Solla"). **Recomendação:** A. _(decidido — A)_
|
||||
- **Quais artigos entram no bento?** **Opções:** A) os N mais recentes visíveis, qualquer tipo de post (noticia/campanha/artigo/evento) | B) só `noticia` (igual à rota `/artigos`). **Recomendação:** A — a home de campanha agrega tudo que estiver visível; o filtro por tipo fica barato depois se a assessoria pedir. _(decidido — A)_
|
||||
- **Mobile: 1 conteúdo por tela?** **Opções:** A) carrossel de 1 card por vez (decisão do cliente nesta sessão) | B) empilhado. **Recomendação:** A. _(decidido — A)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #17
|
||||
- Rascunho UI (gate): `docs/plans/secao-conteudos-home-ui-draft.html` + PNGs acima
|
||||
- Wireframe aprovado: `docs/campanha/wireframe-solla-1313.html` (seção 7 "Acompanhe de perto")
|
||||
- Plano geral do site: `docs/campanha/plano-site-campanha-2026.md` (§4.2 engenharia do board, §3 posições)
|
||||
- `src/utilities/posts.ts` — visibilidade/cache/rotas canônicas de artigos
|
||||
- `src/app/(frontend)/(home)/page.tsx` — onde a seção entra
|
||||
- `AGENTS.md` — Posts & Tags (visibilidade `hidden` fail-closed, cache `posts`)
|
||||
93
docs/plans/secao-conteudos-home-instagram.md
Normal file
93
docs/plans/secao-conteudos-home-instagram.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Seção de conteúdos na home de campanha — Instagram (S3)
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-17
|
||||
Issue: #20
|
||||
Priority: P1
|
||||
Model: cursor-grok-4.5-medium
|
||||
Impeccable: B — estende a seção S1/S2 com cards de Instagram (mesma estrutura, badge "Instagram")
|
||||
Rascunho UI: docs/plans/secao-conteudos-home-ui-draft.html + PNGs embutidos abaixo
|
||||
Appetite: ~1–2 dias eng; integração de leitura com a Graph API + cards na seção
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
A seção "Acompanhe de perto" (S1 artigos + S2 YouTube) ganha os posts do Instagram oficial (`@depjorgesolla`). Instagram é onde a campanha mais posta no dia a dia (bastidores, caravanas, memes, avisos) — é a fonte que dá o ritmo de "atividade agora". A fatia segue o desenho aprovado do plano-site: automático via Instagram Graph API (conta Business/Creator + app Meta), servidor-side, sem script de embed no load; clique abre o post **na plataforma**.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** visitante da home de campanha, majoritariamente mobile, que quer ver a campanha pulsando hoje.
|
||||
- **Job principal:** ver os posts recentes do Instagram sem sair do fluxo da página e abrir o que chamar atenção direto no app/rede.
|
||||
- **Fluxo desejado:** rola até a seção → vê cards 1:1 com badge "Instagram", legenda e data → clica → abre o post no Instagram (nova aba, `noopener`), mantendo a home aberta.
|
||||
- **Anti-goals de produto:** nenhum script/embed pesado do Instagram no load (LCP do mobile — decisão explícita); sem lightbox; o board nunca quebra se o token expirar; IG só liga depois do setup da Meta (review leva dias — sequenciar go-live).
|
||||
|
||||
### Esboço de fluxo (B)
|
||||
|
||||
```text
|
||||
[seção S1+S2 + cards IG] → [clique no card IG] → [instagram.com/... nova aba] → [volta à home intacta]
|
||||
Token expirado/API fora → [mantém último snapshot / oculta só os cards IG — nunca quebra a página]
|
||||
```
|
||||
|
||||
### Rascunho UI (B)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Fonte iterável: [`secao-conteudos-home-ui-draft.html`](secao-conteudos-home-ui-draft.html). A cena `desktop` mostra o bento final; nesta fatia S3 entram os cards Instagram (1:1).
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- A seção passa a incluir os posts mais recentes da conta oficial: cards 1:1 com badge "Instagram", legenda (título) e data; clique abre o post na plataforma (nova aba, `noopener`). **Mobile: carrossel de 1 conteúdo por tela (decisão do cliente).**
|
||||
- Fonte automática: leitura servidor-side via Instagram Graph API (token long-lived com refresh, perfil Business/Creator) com cache — nenhuma chave no cliente, nenhum embed no load.
|
||||
- **Exclusão por item (obrigatório — posts de grade):** o perfil do Instagram tem imagens publicadas SÓ para montar o grid do feed (ex.: grade 3×3 em mosaico), que não são conteúdo real de campanha. O admin precisa marcar posts específicos como "não exibir" (por ID da mídia), e eles somem do board — o carrossel/bento pula para o próximo elegível. Sem esse mecanismo, a seção pode mostrar mosaicos sem sentido; é o requisito nº 1 desta fatia.
|
||||
- Fail-closed: token expirado/API fora/quota → mantém último snapshot em cache; sem snapshot, a seção segue com as outras fontes — a página nunca quebra nem mostra erro.
|
||||
- **Configuração no admin** conforme plano-site §4.2 (sem trava de schema nesta intenção); **sem credenciais IG configuradas, os cards IG simplesmente não aparecem** (a seção vive com artigos + YouTube).
|
||||
- Kill switch "pausar feed" do plano-site vale para o board como um todo.
|
||||
- Zero mudança em schema de conteúdo público; migrações não destrutivas no máximo (config no admin).
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Sim, superfície neste item — metadados do post (imagem, legenda, data) vindos da plataforma.
|
||||
- **Decisões desbloqueadas:** o visitante decide qual post abrir; nada de métricas inventadas.
|
||||
- **Forma:** *adiada ao plano de implementação* — restrição de produto: legenda/data como a plataforma mostra; sem contadores derivados.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** mesmo componente de seção/card de S1/S2 (`src/components/`, `src/app/(frontend)/(home)/page.tsx`, bloco `campaign-site` em `styles.css`); loader servidor-side novo com cache (`src/utilities/` ou `src/lib/`); config no admin (global do Payload, grupo `Configurações`).
|
||||
- **Precedente a olhar:** S1/S2 (estrutura); `docs/campanha/plano-site-campanha-2026.md` §4.2 (Graph API, token long-lived com refresh ~60 dias, kill switch, "IG só liga após setup da Meta"); `src/utilities/posts.ts` (padrão de cache).
|
||||
- **Risco de acoplamento:** mesma generalização da seção — card de conteúdo único (Artigo/YouTube/Instagram) sem código duplicado por plataforma; o setup da Meta é sequenciamento de go-live (externo), não bloqueia a implementação.
|
||||
|
||||
## Dependências
|
||||
|
||||
- **S2** (estrutura da seção completa: artigos + YouTube) — dura.
|
||||
- Soft: `docs/campanha/plano-site-campanha-2026.md` §4.2 + pendência §5 ("mix mandato/campanha no board").
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Compartilhamento WhatsApp → S4 (issue separada).
|
||||
- Script de embed do Instagram no load (proibido pelo plano-site).
|
||||
- Curadoria manual além da exclusão por item (etiquetas, ordenação manual, destaques); stories; DMs; estatísticas além do básico do post; outras contas.
|
||||
- Setup da Meta (app/credenciais) é tarefa da assessoria/produção — a implementação só consome as credenciais quando existirem.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Embed no load.** Se alguém "só completar": o script do Instagram derruba o LCP (decisão explícita do plano-site). **Corte:** thumbnail + link para a plataforma.
|
||||
- **Refresh de token como feature de produto.** Se alguém "só completar": vira um painel de OAuth. **Corte:** token long-lived com refresh automático conforme o plano-site; falha → fail-closed (snapshot/oculta).
|
||||
- **IG sem credencial = erro.** Se alguém "só completar": a seção mostra erro de configuração. **Corte:** sem credencial, cards IG não existem — nada de aviso.
|
||||
- **Exclusão vira curadoria pesada.** Se alguém "só completar": lista enorme de IDs, razões obrigatórias, aprovação. **Corte:** marcar/desmarcar item (thumbnail + ID) no admin; sem workflow.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Mix mandato/campanha no board** — mesma questão da S2: **Opções:** A) automático (recomendação — pendência já registrada no plano-site §5, decidir com a assessoria) | B) filtrar por hashtag/tag. **Recomendação:** A. _(decidido — A + exclusão por item)_
|
||||
- **Exclusão por item: o que aparece para marcar?** **Opções:** A) o admin vê a lista dos últimos posts (thumbnail + ID) e marca os que não devem aparecer (recomendação — sem isso, marcar por ID puro é inviável para a assessoria) | B) só campo de IDs com documentação. **Recomendação:** A — a interface de exclusão é parte desta fatia. _(assumido — validar com produto)_
|
||||
- **Grade do feed (grid) entra?** **Opções:** A) posts de grade entram no automático e são excluídos um a um pela assessoria quando aparecem (recomendação — simples, transparente) | B) tentar detectar grade por heurística e já ocultar. **Recomendação:** A — heurística de "post de grade" é frágil (o IG não sinaliza); a exclusão manual resolve o caso real. _(assumido — validar com produto)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #20
|
||||
- Rascunho UI (gate): `docs/plans/secao-conteudos-home-ui-draft.html` + PNGs acima
|
||||
- `docs/campanha/plano-site-campanha-2026.md` §4.2 — decisões do board IG (Graph API, token, kill switch, sem embed) e §5 pendência "mix mandato/campanha"
|
||||
- Wireframe: `docs/campanha/wireframe-solla-1313.html` (seção 7)
|
||||
- `docs/plans/secao-conteudos-home-artigos.md` (S1) e `secao-conteudos-home-youtube.md` (S2)
|
||||
- `AGENTS.md` — padrões de cache, admin em pt, convenções de nome
|
||||
BIN
docs/plans/secao-conteudos-home-ui-draft-compartilhar.png
Normal file
BIN
docs/plans/secao-conteudos-home-ui-draft-compartilhar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
BIN
docs/plans/secao-conteudos-home-ui-draft-desktop.png
Normal file
BIN
docs/plans/secao-conteudos-home-ui-draft-desktop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
BIN
docs/plans/secao-conteudos-home-ui-draft-mobile.png
Normal file
BIN
docs/plans/secao-conteudos-home-ui-draft-mobile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
docs/plans/secao-conteudos-home-ui-draft-vazio.png
Normal file
BIN
docs/plans/secao-conteudos-home-ui-draft-vazio.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
285
docs/plans/secao-conteudos-home-ui-draft.html
Normal file
285
docs/plans/secao-conteudos-home-ui-draft.html
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
<!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 — Seção de conteúdos 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 pública de campanha (jorgesolla1313). Seção 3 da página: logo após a
|
||||
prova social, imediatamente antes de "Por que essa eleição importa". Card de conteúdo
|
||||
generalizado (Artigo / YouTube / Instagram) — clique leva ao artigo ou à plataforma.
|
||||
</p>
|
||||
|
||||
<!-- ============ CENA: desktop (estado final, 3 fontes) ============ -->
|
||||
<section data-shot="desktop" class="mt-8 rounded-2xl bg-white p-6 text-zinc-900 shadow-xl">
|
||||
<!-- contexto: prova social (barra) -->
|
||||
<div class="flex items-center justify-center gap-10 rounded-xl bg-zinc-100 py-3">
|
||||
<span class="text-sm font-bold text-zinc-400">3.333 proposições</span>
|
||||
<span class="text-sm font-bold text-zinc-400">1.031 discursos</span>
|
||||
<span class="text-sm font-bold text-zinc-400">3º mandato</span>
|
||||
</div>
|
||||
|
||||
<!-- ===== SEÇÃO DE CONTEÚDOS (posição 3) ===== -->
|
||||
<div class="mt-6">
|
||||
<div class="flex flex-wrap items-end justify-between gap-3">
|
||||
<div>
|
||||
<p class="text-xs font-extrabold tracking-[0.14em] text-zinc-500 uppercase">
|
||||
Acompanhe de perto
|
||||
</p>
|
||||
<h2 class="mt-1 text-2xl font-extrabold text-zinc-900">
|
||||
A caminhada, em tempo real
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-zinc-500">
|
||||
Bastidores, caravanas e as lutas do mandato: conteúdo atualizado, direto das redes.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-4 text-sm font-bold">
|
||||
<a href="#" class="text-red-700 underline-offset-4 hover:underline">Ver artigos →</a>
|
||||
<a href="#" class="text-red-700 underline-offset-4 hover:underline">Seguir no Instagram →</a>
|
||||
<a href="#" class="text-red-700 underline-offset-4 hover:underline">YouTube →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- bento: 1 grande + 4 pequenos -->
|
||||
<div class="mt-5 grid gap-4 md:grid-cols-4">
|
||||
<!-- card grande: artigo destaque -->
|
||||
<a href="#" class="group col-span-2 row-span-2 flex flex-col gap-3 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-[16/9] overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
Artigo
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
capa 16:9 (placeholder)
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col gap-1">
|
||||
<h3 class="text-base leading-snug font-extrabold text-zinc-900 group-hover:underline">
|
||||
Título do artigo em destaque, duas ou três linhas para caber
|
||||
</h3>
|
||||
<p class="text-xs leading-relaxed text-zinc-500">
|
||||
Resumo curto do artigo quando houver, uma linha de contexto.
|
||||
</p>
|
||||
<span class="mt-auto text-xs text-zinc-400">há 1 dia · categoria</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- pequeno: vídeo YouTube -->
|
||||
<a href="#" class="group flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-video overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
YouTube
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
thumb 16:9
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="text-sm leading-snug font-extrabold text-zinc-900 group-hover:underline">
|
||||
Título do vídeo recente, até duas linhas
|
||||
</h3>
|
||||
<span class="text-xs text-zinc-400">há 2 dias · 12,4 mil visualizações</span>
|
||||
</a>
|
||||
|
||||
<!-- pequeno: vídeo YouTube -->
|
||||
<a href="#" class="group flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-video overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
YouTube
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
thumb 16:9
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="text-sm leading-snug font-extrabold text-zinc-900 group-hover:underline">
|
||||
Título do segundo vídeo, até duas linhas
|
||||
</h3>
|
||||
<span class="text-xs text-zinc-400">há 5 dias · 8,1 mil visualizações</span>
|
||||
</a>
|
||||
|
||||
<!-- pequeno: Instagram -->
|
||||
<a href="#" class="group flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-square overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
Instagram
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
post 1:1
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="text-sm leading-snug font-extrabold text-zinc-900 group-hover:underline">
|
||||
Legenda do post recente, até duas linhas
|
||||
</h3>
|
||||
<span class="text-xs text-zinc-400">há 3 dias</span>
|
||||
</a>
|
||||
|
||||
<!-- pequeno: Instagram -->
|
||||
<a href="#" class="group flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-square overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
Instagram
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
post 1:1
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="text-sm leading-snug font-extrabold text-zinc-900 group-hover:underline">
|
||||
Legenda do segundo post, até duas linhas
|
||||
</h3>
|
||||
<span class="text-xs text-zinc-400">há 6 dias</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ===== FIM DA SEÇÃO DE CONTEÚDOS ===== -->
|
||||
|
||||
<!-- contexto: "Por que essa eleição importa" (barra) -->
|
||||
<div class="mt-6 rounded-xl bg-zinc-900 px-6 py-5 text-white">
|
||||
<p class="text-xs font-extrabold tracking-[0.14em] text-zinc-400 uppercase">
|
||||
Por que essa eleição importa
|
||||
</p>
|
||||
<p class="mt-1 text-lg font-extrabold">
|
||||
Eleger deputado é coisa séria. O Congresso tem nas mãos vidas reais e o SUS.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ CENA: mobile (carrossel — 1 conteúdo por tela) ============ -->
|
||||
<section data-shot="mobile" class="mt-8 w-[390px] rounded-2xl bg-white p-4 text-zinc-900 shadow-xl">
|
||||
<!-- contexto: prova social -->
|
||||
<div class="flex items-center justify-center gap-6 rounded-xl bg-zinc-100 py-2.5">
|
||||
<span class="text-xs font-bold text-zinc-400">3.333 proposições</span>
|
||||
<span class="text-xs font-bold text-zinc-400">1.031 discursos</span>
|
||||
<span class="text-xs font-bold text-zinc-400">3º mandato</span>
|
||||
</div>
|
||||
|
||||
<!-- seção -->
|
||||
<div class="mt-5">
|
||||
<p class="text-xs font-extrabold tracking-[0.14em] text-zinc-500 uppercase">
|
||||
Acompanhe de perto
|
||||
</p>
|
||||
<h2 class="mt-1 text-xl font-extrabold text-zinc-900">A caminhada, em tempo real</h2>
|
||||
<p class="mt-1 text-sm text-zinc-500">
|
||||
Bastidores, caravanas e as lutas do mandato: conteúdo atualizado, direto das redes.
|
||||
</p>
|
||||
|
||||
<!-- carrossel: 1 card por tela + dots -->
|
||||
<div class="mt-4 overflow-hidden rounded-xl">
|
||||
<!-- card ativo -->
|
||||
<a href="#" class="group flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-video overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
YouTube
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
thumb 16:9
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="text-sm leading-snug font-extrabold text-zinc-900 group-hover:underline">
|
||||
Título do vídeo recente, até duas linhas
|
||||
</h3>
|
||||
<span class="text-xs text-zinc-400">há 2 dias · 12,4 mil visualizações</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- dots de navegação -->
|
||||
<div class="mt-3 flex items-center justify-center gap-2" aria-label="Página do carrossel">
|
||||
<span class="h-2 w-2 rounded-full bg-zinc-300"></span>
|
||||
<span class="h-2 w-2 rounded-full bg-zinc-900"></span>
|
||||
<span class="h-2 w-2 rounded-full bg-zinc-300"></span>
|
||||
<span class="h-2 w-2 rounded-full bg-zinc-300"></span>
|
||||
<span class="h-2 w-2 rounded-full bg-zinc-300"></span>
|
||||
</div>
|
||||
<p class="mt-2 text-center text-xs font-semibold text-zinc-500">1 de 5 · deslize para ver os próximos</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ CENA: card com compartilhar (S4 — WhatsApp) ============ -->
|
||||
<section data-shot="compartilhar" class="mt-8 rounded-2xl bg-white p-6 text-zinc-900 shadow-xl">
|
||||
<p class="text-sm font-bold text-zinc-700">
|
||||
Card de conteúdo com botão discreto de compartilhamento (canto do card, sem competir com
|
||||
o CTA primário): abre WhatsApp com mensagem pré-configurada + opção de copiar link.
|
||||
</p>
|
||||
<div class="mt-4 grid max-w-3xl grid-cols-3 gap-4">
|
||||
<div class="group relative flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-video overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
YouTube
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
thumb 16:9
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="text-sm leading-snug font-extrabold text-zinc-900">
|
||||
Título do vídeo recente, até duas linhas
|
||||
</h3>
|
||||
<span class="text-xs text-zinc-400">há 2 dias · 12,4 mil visualizações</span>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute top-4 right-4 flex h-7 w-7 items-center justify-center rounded-full bg-white text-xs font-bold text-zinc-700 shadow"
|
||||
aria-label="Compartilhar"
|
||||
>
|
||||
↗
|
||||
</button>
|
||||
</div>
|
||||
<div class="group relative flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3">
|
||||
<div class="relative aspect-video overflow-hidden rounded-lg bg-zinc-200">
|
||||
<span class="absolute top-2 left-2 rounded-full bg-zinc-800 px-2 py-0.5 text-[10px] font-extrabold tracking-wider text-white uppercase">
|
||||
Artigo
|
||||
</span>
|
||||
<span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-zinc-400">
|
||||
capa 16:9
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="text-sm leading-snug font-extrabold text-zinc-900">
|
||||
Título do artigo, até duas linhas
|
||||
</h3>
|
||||
<span class="text-xs text-zinc-400">há 1 dia · categoria</span>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute top-4 right-4 flex h-7 w-7 items-center justify-center rounded-full bg-white text-xs font-bold text-zinc-700 shadow"
|
||||
aria-label="Compartilhar"
|
||||
>
|
||||
↗
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center gap-2 rounded-xl border border-dashed border-zinc-300 bg-zinc-50 p-3">
|
||||
<p class="text-xs font-semibold text-zinc-500">
|
||||
Menu aberto (v1): "Compartilhar no WhatsApp" (mensagem pré-configurada com título +
|
||||
link) e "Copiar link".
|
||||
</p>
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-2 text-xs font-semibold text-zinc-700">
|
||||
WhatsApp ↗
|
||||
</div>
|
||||
<div class="rounded-lg border border-zinc-200 bg-white p-2 text-xs font-semibold text-zinc-700">
|
||||
Copiar link
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ CENA: vazio (fail-closed) ============ -->
|
||||
<section data-shot="vazio" class="mt-8 rounded-2xl bg-white p-6 text-zinc-900 shadow-xl">
|
||||
<p class="text-sm font-bold text-zinc-700">
|
||||
Vazio / fail-closed — nenhuma fonte com conteúdo disponível (artigos invisíveis ou APIs
|
||||
sem snapshot). Recomendação: a seção inteira é ocultada; a página mantém o fluxo
|
||||
Prova → Por que essa eleição importa, sem zona morta.
|
||||
</p>
|
||||
<div class="mt-4 flex items-center justify-center gap-10 rounded-xl bg-zinc-100 py-3">
|
||||
<span class="text-sm font-bold text-zinc-400">3.333 proposições</span>
|
||||
<span class="text-sm font-bold text-zinc-400">1.031 discursos</span>
|
||||
<span class="text-sm font-bold text-zinc-400">3º mandato</span>
|
||||
</div>
|
||||
<div class="mt-4 rounded-xl bg-zinc-900 px-6 py-5 text-white">
|
||||
<p class="text-xs font-extrabold tracking-[0.14em] text-zinc-400 uppercase">
|
||||
Por que essa eleição importa
|
||||
</p>
|
||||
<p class="mt-1 text-lg font-extrabold">
|
||||
Eleger deputado é coisa séria. O Congresso tem nas mãos vidas reais e o SUS.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
93
docs/plans/secao-conteudos-home-youtube.md
Normal file
93
docs/plans/secao-conteudos-home-youtube.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Seção de conteúdos na home de campanha — YouTube (S2)
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-17
|
||||
Issue: #18
|
||||
Priority: P1
|
||||
Model: cursor-grok-4.5-medium
|
||||
Impeccable: B — estende a seção S1 com cards de vídeo (mesma estrutura de card, badge "YouTube")
|
||||
Rascunho UI: docs/plans/secao-conteudos-home-ui-draft.html + PNGs embutidos abaixo
|
||||
Appetite: ~1–2 dias eng; integração de leitura com a API do YouTube + cards na seção S1
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
A seção "Acompanhe de perto" da home de campanha (criada em S1 com artigos) ganha os vídeos do canal oficial. O canal já existe (`@JorgeSollaDep`) e posta com frequência — vídeos são o conteúdo de maior engajamento na reta final. A fatia segue o desenho aprovado no plano do site: automático via API do YouTube, servidor-side, sem iframe no carregamento; clique abre o vídeo **na plataforma** (decisão do wireframe).
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** visitante da home de campanha que quer ver a caminhada em movimento (bastidores, caravanas, entrevistas).
|
||||
- **Job principal:** ver que o canal está ativo e assistir o vídeo mais recente sem caçar o canal.
|
||||
- **Fluxo desejado:** rola até a seção → vê o card grande do último vídeo (thumbnail 16:9 + badge "YouTube" + título + views/data) e cards menores dos seguintes → clica no card → abre o vídeo no YouTube (nova aba, `noopener`), mantendo a home aberta.
|
||||
- **Anti-goals de produto:** nenhum embed/player inline no v1 (decisão do plano-site §4.2: "sem iframe no load", LCP do mobile); o board não é curadoria manual; a seção nunca quebra se a API falhar.
|
||||
|
||||
### Esboço de fluxo (B)
|
||||
|
||||
```text
|
||||
[seção S1 + cards YT] → [clique no card YT] → [youtube.com/... nova aba] → [volta à home intacta]
|
||||
API indisponível → [mantém último snapshot / oculta só os cards YT — nunca quebra a página]
|
||||
```
|
||||
|
||||
### Rascunho UI (B)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Fonte iterável: [`secao-conteudos-home-ui-draft.html`](secao-conteudos-home-ui-draft.html). A cena `desktop` mostra o bento final (Artigo + YouTube + Instagram); nesta fatia S2 entram só os cards YouTube.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- A seção S1 passa a incluir os vídeos mais recentes do canal oficial: card grande = último vídeo (16:9), pequenos = próximos, com badge "YouTube", título, data e visualizações. **Mobile: carrossel de 1 conteúdo por tela (decisão do cliente).**
|
||||
- Fonte automática: leitura servidor-side da API pública do YouTube (dados dos últimos vídeos do canal), com cache (ISR/revalidação) — nenhuma chave no cliente, nenhum iframe no load.
|
||||
- Clique no card abre o vídeo **na plataforma** (URL canônica do vídeo), em nova aba com `noopener` — sem lightbox, sem player inline (decisão do wireframe; player inline fica fora de escopo).
|
||||
- **Exclusão por item (curadoria mínima):** o admin pode marcar vídeos específicos para NÃO aparecer (ex.: vídeo errado, conteúdo que não é de campanha, transmissão incompleta). Itens excluídos não são exibidos nem contam para "o último vídeo" — o board pula para o próximo elegível. Mesmo mecanismo de exclusão das outras plataformas (S3), configurado no mesmo lugar no admin.
|
||||
- Fail-closed: API sem resposta/token expirado/quota estourada → mantém o último snapshot em cache se existir; sem snapshot, a seção continua com as outras fontes (ou oculta por completo se nada houver) — a página nunca quebra nem mostra erro.
|
||||
- A configuração (chave/IDs + exclusões) vive no admin, seguindo o desenho do plano-site §4.2 (sem trava de schema nesta intenção — o executor define a forma); sem chave configurada, os cards YT simplesmente não aparecem.
|
||||
- Zero mudança em schema de conteúdo público / migrations destrutivas; a visibilidade eleitoral `hidden` dos posts não se aplica aqui (fonte externa), mas o kill switch do feed (pausar) segue o desenho do plano-site.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Sim, superfície neste item — metadados do vídeo (título, thumbnail, data, visualizações) vindos da plataforma.
|
||||
- **Decisões desbloqueadas:** o visitante decide qual vídeo assistir (clique); visualizações são fato da plataforma (não inventar).
|
||||
- **Forma:** *adiada ao plano de implementação* — restrição de produto: mostrar views como a plataforma mostra (ex. "12,4 mil"), nunca métrica derivada da campanha.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** mesmo componente de seção/card de S1 (`src/components/`, `src/app/(frontend)/(home)/page.tsx`, bloco `campaign-site` em `styles.css`); loader/fetch servidor-side novo em `src/utilities/` ou `src/lib/` com cache (padrão `unstable_cache` do repo); config no admin (global do Payload, grupo `Configurações` — sem nome de arquivo travado).
|
||||
- **Precedente a olhar:** S1 (estrutura da seção); `docs/campanha/plano-site-campanha-2026.md` §4.2 (decisões: Data API v3, server-side, ISR, thumbnails CDN, sem iframe no load); padrões de cache do repo (`src/utilities/posts.ts`, `unstable_cache` + tags); `seed-posts.mjs` se precisar de referência de chamada externa com cache de download.
|
||||
- **Risco de acoplamento:** seção compartilhada com S3 (Instagram) — a estrutura de card generalizada criada em S1 não pode virar código duplicado por plataforma; o kill switch de "pausar feed" do plano-site é um toggle único do board (não por plataforma na intenção — validar no plano de implementação).
|
||||
|
||||
## Dependências
|
||||
|
||||
- **S1** (estrutura da seção + card generalizado) — dura.
|
||||
- Soft: `docs/campanha/plano-site-campanha-2026.md` §4.2 (decisões de engenharia do board).
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Instagram → S3 (mesma seção, mesmo lote).
|
||||
- Compartilhamento WhatsApp → S4 (issue separada).
|
||||
- Player inline / lightbox / iframe no load (decisão do wireframe: clique abre na plataforma).
|
||||
- Curadoria manual além da exclusão por item (playlists, etiquetas, ordenação manual, seleção de destaques); download/armazenamento dos vídeos; estatísticas além do que a API entrega (comentários, inscritos).
|
||||
- Outros canais/contas (a configuração aponta um canal oficial).
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Embed no load.** Se alguém "só completar": iframes de YouTube derrubam o LCP no mobile (decisão explícita do plano-site §4.2). **Corte:** thumbnail + link para a plataforma.
|
||||
- **Vídeo "em destaque" com escolha manual.** Se alguém "só completar": vira curadoria semanal. **Corte:** automático (último vídeo elegível = card grande).
|
||||
- **Exclusão vira curadoria pesada.** Se alguém "só completar": lista enorme de IDs, razões obrigatórias, aprovação. **Corte:** marcar/desmarcar item no admin; sem workflow.
|
||||
- **Fail-closed vira erro visível.** Se alguém "só completar": mensagem de "erro ao carregar" queima a home. **Corte:** seção nunca mostra erro — snapshot ou ocultação silenciosa.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Misturar mandato e campanha no board?** **Opções:** A) automático — expõe o que o canal postar (recomendação: pendência já registrada no plano-site §5, decidir com a assessoria antes do go-live) | B) filtrar por termo/playlist. **Recomendação:** A, com o kill switch do plano-site + exclusão por item como rede de segurança. _(decidido — A + exclusão por item)_
|
||||
- **Exclusão por item: qual granularidade?** **Opções:** A) lista de IDs excluídos por plataforma, gerenciada no admin (recomendação — simples, auditável, suficiente para vídeos errados/indesejados) | B) razão/etiqueta obrigatória por exclusão. **Recomendação:** A — o motivo pode ser um campo opcional de texto livre, sem virar workflow. _(assumido — validar com produto)_
|
||||
|
||||
## Referências
|
||||
|
||||
- GitHub Issue #18
|
||||
- Rascunho UI (gate): `docs/plans/secao-conteudos-home-ui-draft.html` + PNGs acima
|
||||
- `docs/campanha/plano-site-campanha-2026.md` §4.2 — decisões do board (API, cache, sem iframe, fail-closed) e §5 pendência "mix mandato/campanha"
|
||||
- Wireframe: `docs/campanha/wireframe-solla-1313.html` (seção 7)
|
||||
- `docs/plans/secao-conteudos-home-artigos.md` (S1 — estrutura que esta fatia estende)
|
||||
- `AGENTS.md` — padrões de cache (`unstable_cache`), admin em pt, convenções de nome (identificadores em inglês)
|
||||
Loading…
Reference in a new issue