diff --git a/docs/plans/central-conteudos-analytics-ui-design.html b/docs/plans/central-conteudos-analytics-ui-design.html new file mode 100644 index 00000000..aa328b58 --- /dev/null +++ b/docs/plans/central-conteudos-analytics-ui-design.html @@ -0,0 +1,374 @@ + + + + + + + Design — C213 · Analytics da Central + + + +
+
+ C213 · revisão do gate +

Quatro sinais. Nenhum dashboard.

+

+ Os contadores vivem junto da peça e respondem só ao que a assessoria precisa decidir. +

+
+ +
+
+ CENA 01 +

Desktop 1280 · uma coluna “Circulação” na lista

+
+
+
+ +
+
+
+

Conteúdos

+

+ Publicação e circulação no mesmo lugar. +

+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PeçaPublicaçãoCirculaçãoAção
+
+
NEEDS ASSET
+
+ Fim da escala 6×1 é saúde +

Vídeo

+
+
+
Publicado +
+
+ Aberturas +
+
+ Downloads +
+
+ WhatsApp +
+
+ Link +
+
+
+ Solla em defesa do SUS +

Foto

+
Publicado + 0 abertura · 0 download · 0 WhatsApp · 0 link +
+ Por que defender o SUS +

Texto

+
RascunhoSem dados — ainda não publicada
+
+

+ Barras cinza = valores reais omitidos no gate · 0 = nenhum evento · — = contagem + indisponível. +

+
+
+
+
+ +
+
+ CENA 02 +

Desktop 1280 · detalhe por canal, sem gráfico

+
+
+
+ ← Conteúdos +

Fim da escala 6×1 é saúde

+
+
+
+
NEEDS ASSET · PREVIEW REAL
+ +
+
+

Circulação

+

+ Contagem anônima e acumulada desde a publicação. +

+
+
+ Aberturas +
+
+ Downloads +
+
+ WhatsApp +
+
+ Link copiado +
+
+

+ Valores reais omitidos neste gate; o produto mostra contagens absolutas. +

+
+ Leitura: compare os sinais sem somá-los. WhatsApp e + link ficam separados porque mostram escolhas diferentes. +
+

+ Sem IP persistido, cookie de identidade ou rastreio entre peças. +

+
+
+
+
+ +
+
+ CENAS 03–04 +

Mobile 390 · cards e falha da contagem

+
+
+
+
+ Conteúdos +
+
+ +
+
+ Fim da escala 6×1 é saúdePublicado +
+
+
+ Aberturas +
+
+ Downloads +
+
+ WhatsApp +
+
+ Link +
+
+ +
+
+
+ Solla em defesa do SUSPublicado +
+

+ 0 abertura · 0 download · 0 WhatsApp · 0 link +

+
+
+
+ Por que defender o SUSRascunho +
+

Sem dados — ainda não publicada.

+
+
+
+
+
+ ←Detalhe da peça +
+
+
NEEDS ASSET · PREVIEW REAL
+

Fim da escala 6×1 é saúde

+

Circulação

+
+
Aberturas—
+
Downloads—
+
WhatsApp—
+
+ Link copiado— +
+
+
+ Contagem indisponível agora. A página pública, o download e o compartilhamento + continuam funcionando. +
+ +
+
+
+
+
+ + diff --git a/docs/plans/central-conteudos-analytics.md b/docs/plans/central-conteudos-analytics.md new file mode 100644 index 00000000..98e88344 --- /dev/null +++ b/docs/plans/central-conteudos-analytics.md @@ -0,0 +1,112 @@ +# C213 — Analytics da Central de Conteúdos — uso, downloads e compartilhamentos + +Status: rascunho +Atualizado em: 2026-09-22 +Issue: #1258 +Priority: P2 +Impeccable: B — encaixe na lista de peças do C211 (contadores) sem tela nova +Design UI: docs/plans/central-conteudos-analytics-ui-design.html +Appetite: ~1–1,5 dia eng; um outcome verificável — contadores por peça na lista do C211, sem serviço novo de analytics +Responsável: — + +## Intenção + +A Central de Conteúdos (C211 + S27) existe para a assessoria publicar peças e o público abrir, baixar e compartilhar. Mas hoje ninguém sabe se isso acontece: o self-hosted não tem analytics ativo (`@vercel/analytics` só rende com `VERCEL === '1'`; o Meta Pixel é mídia paga, não serve) e não há coleção de eventos. O dono pediu "acompanhar a utilização dos usuários e quanto compartilhamentos e downloads estão sendo feitos" — e a pergunta embutida é se vale criar algo próprio ou integrar algo existente. + +Esta fatia responde de forma mínima e anônima: cada peça ganha contadores na lista interna que já existe, sem dashboard novo e sem serviço para operar. A assessoria precisa saber quais peças são abertas, baixadas e compartilhadas; a coordenação precisa saber se o esforço de manter a Central está valendo. Nada além disso. + +## Persona e fluxo + +- **Persona / contexto:** assessoria e coordenação de comunicação (role `communicator`; `coordinator`/`candidate` veem o mesmo), na mesa, decidindo o que reforçar e o que produzir. Quem gera os eventos é o visitante anônimo da página pública — que nunca é identificado. +- **Job principal:** ler, por peça, o que foi aberto, baixado e compartilhado, e decidir o próximo passo de produção sem abrir outra ferramenta. +- **Fluxo desejado:** entra na lista de peças → lê os contadores de cada linha → "muito aberta e pouco compartilhada" pede novo gancho/capa; "muito compartilhada" pede continuação → decide o que reforçar/reeditar e o que produzir em seguida. +- **Anti-goals de produto:** não é analytics de site (sem pageview, funil, origem, heatmap); não é perfil de visitante (sem cookie de identidade, sem IP persistido, sem rastreio entre páginas ou entre peças); não é dashboard novo nem gráfico de vaidade; não rastreia o que acontece depois do clique — fora do site, nada. + +### Esboço de fluxo (B) + +```text +[visita anônima abre a peça] → abertura · download · compartilhar (WhatsApp | link) contam na peça +[assessoria] lista interna de peças (C211) → contadores por linha → "abriu muito, compartilhou pouco" +→ reforça/reedita gancho, capa ou chamada → decide a próxima peça +[coordenação] lê as peças mais servidas → decide se a Central vale o esforço de catalogar/publicar +[falha na contagem] a página pública segue idêntica — download e compartilhar nunca dependem do contador +``` + +### Design UI (B) + +- Design UI (gate): `docs/plans/central-conteudos-analytics-ui-design.html` — cenas: lista de peças do C211 com a coluna de contadores (com e sem dados) e o recorte por canal no detalhe da peça. Encaixe na lista existente; sem tela nova. + +## Objetivo e aceite + +- A lista interna de peças do C211 mostra, por peça, contadores absolutos de aberturas, downloads e compartilhamentos (WhatsApp e link), anônimos e agregados. +- A assessoria responde "qual peça reforçar/reeditar e o que produzir em seguida" e a coordenação responde "a Central está valendo o esforço" lendo a própria lista, sem ferramenta nova. +- Fail-soft: se a contagem falhar, a página pública não quebra nem atrasa; nada bloqueia abertura, download ou compartilhamento — contador a menos é aceitável, dado de visitante não. +- Privacidade: sem PII (sem IP persistido, sem cookie de identidade, sem user-agent completo), sem rastreio entre páginas/peças e sem qualquer dado de eleitor; contagem estritamente anônima. +- Nenhum serviço novo no homeserver para operar/backup; nada de dashboard, gráfico ou rota de analytics. + +## Dados (intenção) + +- **Vou apresentar dados?** Sim, superfície neste item — contadores anônimos por peça (abertura · download · compartilhamento) na lista interna de peças do C211. +- **Decisões desbloqueadas:** + - Assessoria de comunicação: qual peça reforçar/reeditar e o que produzir em seguida (aberta e pouco compartilhada = rever gancho/capa; muito compartilhada = desdobrar). + - Coordenação de comunicação: se a Central está valendo o esforço de catalogar/publicar — as peças estão sendo servidas e circulando? + - Assessoria: qual canal entrega circulação (WhatsApp × link copiado) para concentrar o CTA onde a rede responde. +- **Forma:** _adiada ao plano de implementação_ — restrições: contagens absolutas por peça (sem %; a base é anônima e desconhecida), nunca somadas num índice único de "uso", sem série/tendência no v1, sem KPI de vaidade (tempo, scroll, ranking). + +## Dados da decisão (literais) + +- Eventos v1 (rótulos): "Abertura da peça" · "Download" · "Clique em compartilhar (WhatsApp)" · "Clique em compartilhar (link)" — WhatsApp e link contam **separados** (o canal é a pergunta de produto; somar esconde onde a circulação para). +- "Uso" não vira um número só: os contadores aparecem lado a lado, por peça, sem total "usos" e sem média. +- Nada de PII: sem IP persistido, sem cookie de identidade, sem user-agent completo; contagem anônima e agregada, nunca associável a pessoa; sem rastreio entre páginas ou entre peças. +- Sem `Consent` novo — não há dado pessoal a consentir; qualquer identificação de visitante está fora de escopo (fail-closed de privacidade). +- Superfície: contadores na lista interna de peças (C211) — sem dashboard novo, sem gráfico, sem rota de analytics. +- Decisão própria vs existente: **A** — coleção mínima de eventos anônimos no próprio Payload, escrita por endpoint público fail-soft e agregada na lista do C211; sem serviço novo, sem cookie, atribuição por peça garantida. Alternativas avaliadas: **B** `@10x-media/analytics` (`0.1.0-beta.0`, adapter `native()` self-hosted, rollups no próprio Postgres, superfície no `/admin`) e **C** serviço externo self-hosted (Umami/Plausible — mais um serviço para operar e ainda exigiria eventos customizados). Reavaliar B/C só se a pergunta virar funil/pageview agregado. +- Fail-soft: se a contagem falhar, a página pública não quebra nem atrasa; nada de bloquear abertura, download ou compartilhamento por telemetria. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/collections/` (eventos anônimos por peça), `src/utilities/` (agregação para os contadores), `src/components/campaign/shared/` (coluna/célula na `CampaignTable`) e uma rota pública de escrita em `src/app/(frontend)/api/` chamada pela página do S27. +- **Precedente a olhar:** `src/app/(frontend)/api/revalidate/route.ts` e `src/app/(frontend)/api/social-feed/sync/route.ts` (rota JSON pública, allowlist, fail-soft), `src/components/campaign/shared/CampaignTable.tsx` + `CampaignListOmnibox` + `src/utilities/campaignListUrl.ts` (a superfície), `src/collections/CampaignVoteSummarySnapshot.ts` (contagem/rollup, não dashboard), `src/lib/campaignPageChrome.ts` + `src/components/campaign/shell/nav.ts` (chrome). O rate limit existente (`src/utilities/ai/rateLimit.ts`) é por `userId` e não serve para o público. +- **Risco de acoplamento:** a contagem é acessória — o download/compartilhar e a página do S27 não podem depender dela; a peça é a do C211 (nada de segundo modelo de peça); nenhum identificador de visitante pode nascer daqui. + +## Dependências + +- **S27** (dura) — sem a página pública não há evento a contar. +- **C211** (dura) — a peça catalogada e a lista interna são a superfície dos contadores. +- Soft: **S28** (busca por tema) é ortogonal; os contadores entram como colunas, como as demais. + +## Fora de escopo + +- Funil/pageview agregado do site (visitantes, origem, rejeição) — se pedido, reavaliar plugin (B) ou serviço self-hosted (C) em item próprio. +- Heatmap, scroll depth, tempo na página e A/B de título/capa/CTA. +- Rastrear visitante entre páginas ou entre peças (sessão, device, identidade anônima) — o modelo é evento solto. +- Dashboard, rota de analytics, gráfico de série, exportação e alertas. +- Meta Pixel (mídia paga na home/abaixo-assinado), analytics de terceiros no self-hosted e plataformas externas (Instagram/YouTube). +- UTM/encurtador e medição fora do site — o que acontece depois do `wa.me` ou do link copiado não é medível aqui (já adiado em S4/C166). + +## Rabbit holes de produto + +- **Virar analytics de site.** Se alguém "só completar": pageview, origem, cookie, banner de consent. **Corte neste item:** só eventos de peça, anônimos e sem identidade. +- **Medir a circulação depois do clique.** Se alguém "só completar": encurtador, redirect com token, "quantas pessoas receberam no WhatsApp". **Corte neste item:** o clique é o teto do que o site sabe; pós-clique é fora. +- **Placar único de "uso" / dashboard de vaidade.** Se alguém "só completar": somar tudo num número e desenhar tendência. **Corte neste item:** contadores separados, lado a lado, sem índice composto. +- **Adotar o plugin só pelo widget.** Se alguém "só completar": superfície no `/admin` (errada para a comunicação) e migrations de pacote beta. **Corte neste item:** A; reavaliação B/C só para funil/pageview. +- **Guardar tudo para sempre.** Se alguém "só completar": eventos crus com IP/user-agent e retenção infinita — vira perfil de visitante. **Corte neste item:** mínimo anônimo, sem identificador persistido. + +## Questões em aberto (produto) + +- **Própria, plugin existente ou serviço self-hosted?** **Opções:** A) coleção mínima própria | B) `@10x-media/analytics` (beta) | C) Umami/Plausible self-hosted. **Recomendação:** A — atribuição por peça garantida e superfície onde a assessoria já está, sem serviço novo para operar/backup; B está em beta e vive no `/admin`; C somaria um serviço e ainda exigiria eventos customizados. Reavaliar se a pergunta virar funil/pageview agregado. _(assumido — validar com produto)_ +- **O que conta como "uso"?** **Opções:** A) só download + compartilhar | B) os quatro contadores lado a lado | C) um número "usos" por peça. **Recomendação:** B — a pergunta é "esta peça circula?" e cada contador mostra onde ela para; C esconde a decisão; A descarta o sinal de que a peça foi encontrada. _(assumido — validar com produto)_ +- **Granularidade temporal?** **Opções:** A) acumulado por peça desde a publicação | B) janela de 7 dias | C) série diária. **Recomendação:** A no v1 — responde "reforçar/reeditar" e "vale a pena" sem virar dashboard; janela de 7 dias é o próximo passo registrado se a pergunta virar "o que está circulando agora". _(assumido — validar com produto)_ +- **Onde a assessoria vê?** **Opções:** A) coluna na lista de peças do C211, com recorte por canal no detalhe | B) bloco no topo da Central | C) rota de analytics. **Recomendação:** A — a lista já é a mesa de trabalho; B/C criam superfície nova e puxam para dashboard. _(assumido — validar com produto)_ + +## Referências + +- Design UI (gate): `docs/plans/central-conteudos-analytics-ui-design.html` (+ assets em `central-conteudos-analytics-ui-design-assets/`) +- Planos irmãos: `docs/plans/central-conteudos-publica.md` (S27 — a página que gera os eventos), `docs/plans/central-conteudos-ingestao.md` (C211 — a lista/superfície), `docs/plans/compartilhar-conteudos-home-whatsapp.md` (S4 — "nada é coletado neste item"), `docs/plans/c166-compartilhar-trecho-link.md` (C166 — "sem telemetria de compartilhamento") +- Plugins avaliados (não adotados): `@10x-media/analytics` (10x-media/payload-plugins, `0.1.0-beta.0`, adapter `native()` self-hosted, superfície no `/admin`) e os serviços Umami/Plausible +- Arquivos como pista, não contrato: `src/app/(frontend)/layout.tsx` (analytics Vercel inerte), `src/components/MetaPixel.tsx`, `src/app/(frontend)/api/revalidate/route.ts`, `src/app/(frontend)/api/social-feed/sync/route.ts`, `src/components/campaign/shared/CampaignTable.tsx`, `src/utilities/campaignListUrl.ts`, `src/collections/CampaignVoteSummarySnapshot.ts`, `src/utilities/documents.ts` +- `AGENTS-campaign.md` / `AGENTS.md` — vertical Comunicação, LGPD fail-closed, naming e `overrideAccess: false` + +## Self-score (shaping) + +5/5 — (1) fatia = um outcome verificável (contadores anônimos por peça na lista interna, sem serviço novo); (2) appetite ~1–1,5 dia cabe num encaixe de coluna; (3) persona, job e aceite legíveis sem stack; (4) direção no codebase é hipótese com precedentes abertos; (5) zero decisão dura de engenharia — schema, rota e agregação ficam para a implementação. diff --git a/docs/plans/central-conteudos-busca-semantica-ui-design.html b/docs/plans/central-conteudos-busca-semantica-ui-design.html new file mode 100644 index 00000000..8c30017b --- /dev/null +++ b/docs/plans/central-conteudos-busca-semantica-ui-design.html @@ -0,0 +1,283 @@ + + + + + + + Design — S28 · Busca por tema + + + +
+
+ S28 · revisão do gate +

+ Procure pelo assunto. Entenda cada resultado. +

+

+ Uma escolha clara de modo e uma explicação curta por peça. Nada de score, ruído ou + resultado forçado. +

+
+ +
+
+ CENA 01 +

Desktop 1280 · modo e proveniência, sem chrome extra

+
+
+
+ Jorge SollaCentral de Conteúdos +
+
+

Encontre uma peça para pedir voto

+
+ +
+ Buscar por: +
+ Termo exato✦ Por tema +
+
+
+ Tipo⌄Cidade⌄Tema⌄Mais filtros⌄ +
+
+

Resultado por tema

+
+
NEEDS ASSET · POSTER REAL
+
+ ✦ Tema +

Fim da escala 6×1 é saúde

+

Vídeo · Trabalho · Salvador

+
+ Por que apareceu +

+ “…reduzir a jornada sem reduzir o salário protege a saúde de quem trabalha…” +

+
+ Abrir peça → +
+
+
+
+
+ +
+
+ CENA 02 +

Mobile 390 · uma decisão por vez

+
+
+
+ Jorge Solla☰ +
+
+

Encontre uma peça para pedir voto

+
+ Buscar por: +
+ Termo exato✦ Por tema +
+
+ Tipo⌄Cidade⌄Tema⌄ +
+
+
+
NEEDS ASSET · POSTER REAL
+
+ ✦ Tema +

Fim da escala 6×1 é saúde

+
+ Por que apareceu +

+ “…reduzir a jornada sem reduzir o salário protege a saúde de quem trabalha…” +

+
+ Abrir peça → +
+
+
+
+
+ +
+
+ CENAS 03–04 +

Estados críticos · vazio honesto e degradação

+
+
+
+
+

Nenhuma peça combina bem com esse tema

+

+ Não mostramos um resultado fraco só para preencher a tela. +

+
+ +
+

Vazio · desktop 1280

+
+
+
+
+ Busca por tema indisponível agora.
A busca exata continua funcionando. +
+ Buscar por: +
+ Termo exato⚠ Por tema +
+ +

+ Degradação · mobile 390 · nenhum resultado fantasma. +

+
+
+
+
+ + diff --git a/docs/plans/central-conteudos-busca-semantica.md b/docs/plans/central-conteudos-busca-semantica.md new file mode 100644 index 00000000..780ffd7b --- /dev/null +++ b/docs/plans/central-conteudos-busca-semantica.md @@ -0,0 +1,116 @@ +# S28 — Busca por tema na Central de Conteúdos pública + +Status: rascunho +Atualizado em: 2026-09-22 +Issue: #1257 +Priority: P2 +Impeccable: B — encaixe no campo de busca e na lista da Central (S27) +Design UI: docs/plans/central-conteudos-busca-semantica-ui-design.html +Appetite: ~1–2 dias eng; um outcome verificável — buscar por sentido na Central pública devolve peças publicadas com proveniência e degradação honesta +Responsável: — + +## Intenção + +A Central de Conteúdos pública (S27) deixa o eleitor achar as peças por termo exato — mas o eleitor pensa por assunto, não por palavra: "fim da escala 6x1" e "saúde no subúrbio" não aparecem literalmente em toda peça que trata disso. Sem o modo por tema, a Central só confirma o que o eleitor já sabia procurar; não o ajuda a descobrir. Este item é a fatia de busca-por-tema da Central: a peça certa aparece pelo sentido, com honestidade sobre por que apareceu. + +O precedente é interno e já está em produção: C192 (acervo de falas) provou o mecanismo — expansão do tema por LLM + busca lexical, modo visível, selo por resultado, vazio honesto, degradação com aviso. A diferença crítica aqui é a rota ser PÚBLICA e sem login: não existe limitador anônimo hoje e a expansão não é cacheada — custo aberto é o risco novo, não o mecanismo. P2: a Central já funciona por termo exato; o modo por tema cumpre a intenção do dono, mas não bloqueia o go-live. + +## Persona e fluxo + +- **Persona / contexto:** eleitor sem login, majoritariamente no celular, chegando de link de WhatsApp/Instagram ou de busca, querendo ver o que o Solla fez/falou sobre um assunto. Secundária: assessoria que procura peça para reenviar. +- **Job principal:** achar material sobre um tema pelo sentido, mesmo quando a peça não usa as palavras da busca. +- **Fluxo desejado:** + 1. Digita o tema no campo de busca da Central. + 2. Escolhe como buscar: termo exato (como hoje) ou por tema — a escolha é visível; "Termo exato" é o padrão. + 3. Recebe as peças; cada resultado por tema vem marcado ("Tema") com um indício curto e real de por que apareceu (trecho da descrição/transcrição). + 4. Abre a peça (fluxo público atual da Central) e lê/compartilha. + 5. Se nada servir, vazio honesto com saída (reformular, usar termo exato, limpar filtros) — nunca resultado "parecido" só para preencher a tela. +- **Anti-goals de produto:** não vira gerador gratuito de texto nem buscador geral do site; não expõe o acervo interno de falas, PII ou fala de terceiro fora de peça publicada; não troca a busca exata; não inventa resultado nem mostra score numérico. + +### Esboço de fluxo (B) + +```text +[Central pública] → digita tema → escolhe "Por tema" (modo visível; "Termo exato" é o padrão) + → lista de peças publicadas; card por tema: selo "Tema" + "por que apareceu" (trecho real) + → abre a peça → lê/compartilha + → vazio honesto: reformular | usar termo exato | limpar filtros + → tema indisponível/limite atingido: busca exata continua + aviso discreto +``` + +### Design UI (B) + +- Design UI (gate): `docs/plans/central-conteudos-busca-semantica-ui-design.html` +- Por que B e não A: exige affordance nova (escolher o modo) e estados novos (selo/proveniência, vazio honesto, aviso de degradação) dentro do campo de busca e da lista que o S27 já entrega — sem rota nova. O HTML hi-fi é fonte de verdade do port. + +## Objetivo e aceite + +- Buscar um tema sem as palavras exatas (ex.: "fim da escala 6x1") devolve peças publicadas que tratam do tema, sobre o corpus da Central. +- Todo resultado deixa claro por que apareceu: "Tema" vs "Termo exato", com indício curto e real (trecho da descrição/transcrição) — sem score numérico nem "parecido" enganoso. +- "Termo exato" continua sendo o padrão e o comportamento de hoje não regride. +- Sem resultado quando nada serve: vazio honesto com saída (reformular/trocar modo/limpar filtros); nunca resultado inventado. +- Se o mecanismo por tema falhar/estiver indisponível, degrada para a busca exata com aviso discreto — nunca erro na cara nem resultado fantasma. +- Filtros da Central (cidade, região, categoria, instituição, etc.) seguem valendo junto com a busca, nos dois modos. +- **Guardrails:** a busca cobre SÓ peças publicadas da Central; nada do acervo interno, nada de PII, nada de fala de terceiro fora de peça publicada. A rota é pública: a busca por tema não pode virar custo aberto — precisa de limite de uso (mecanismo a critério da implementação) e as chamadas não podem ser disparadas por bot/crawler; sob abuso, o modo degrada e ninguém usa a Central como gerador gratuito de texto. + +## Dados (intenção) + +- **Vou apresentar dados?** N/A — resultado de busca não é métrica nem agregado; nenhuma decisão numérica é desbloqueada. +- **Decisões desbloqueadas:** N/A — a escolha do eleitor ("qual peça abrir/compartilhar") é qualitativa. +- **Forma:** N/A — sem superfície de dados; restrição de produto: o sinal do resultado é explicação qualitativa (trecho real), nunca score de confiança. + +## Dados da decisão (literais) + +- Modo visível no campo de busca: "Buscar por: Termo exato | Por tema"; "Termo exato" é o padrão. +- Resultado por tema marcado ("Tema") com indício curto e real de por que apareceu (trecho da descrição/transcrição); nunca score numérico nem "parecido" enganoso. +- Vazio honesto com saída: reformular · usar termo exato · limpar filtros. +- Degradação: sem chave, timeout ou limite de uso, a busca exata continua e um aviso discreto explica — nunca erro na cara nem resultado fantasma. +- Guardrail de custo/abuso: limite de uso obrigatório (mecanismo a decidir na implementação); chamada de tema não pode ser disparada por bot/crawler; sob abuso, o modo degrada. +- Corpus: só peças publicadas da Central; nada do acervo interno, nada de PII. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** rota pública da Central em `src/app/(frontend)/` (S27); componentes da Central (campo de busca/lista/card); `src/utilities/ai/` (expansão + limitador anônimo novo); `src/lib/` (normalização/sanitização); loader da coleção de peças do C211. +- **Reuso do C192 (pista, não contrato):** `src/utilities/ai/expandSpeechSearchTheme.ts` (contrato `null` em falha, timeout), `src/lib/speechThemeTerms.ts` (sanitização dos termos do LLM), `src/utilities/speech/speechListFilters.ts` (OR textual por termo), `src/lib/speechSearch.ts` (`normalizeForSearch` + espelho), `src/utilities/speech/speechListUrl.ts` (`mode=tema` só com `q`); UI para inspirar: `SpeechAcervoFilters.tsx`, `SpeechResultCard.tsx` (selo "Tema" + "Por que apareceu"), `SpeechThemeFallbackNotice.tsx`. +- **A diferença da rota pública (o que o executor não pode copiar):** o rate limit existente (`src/utilities/ai/rateLimit.ts`) é chaveado por `userId` e só roda atrás de auth — não serve aqui; a expansão não é cacheada; `DEEPSEEK_API_KEY` é global. Corpus provavelmente um `searchText` normalizado por peça (padrão `Speech.searchText`/`Recording.searchText`), com índice trigram como precedente (`src/migrations/20260913_001200_add_speech_segment_trgm_index.ts`). +- **Risco de acoplamento:** não expor acervo interno nem PII por descuido de `depth`/relação; não quebrar a busca exata nem o contrato de URL/filtros do S27; rota nova em `(frontend)` acorda os specs públicos no manifesto e2e (`scripts/lib/e2e-affected-manifest.mjs`). + +## Dependências + +- S27 (dura) — a página pública da Central e seu campo de busca/lista; sem ela não há onde encaixar o modo. +- C211 (dura) — as peças catalogadas (título, descrição, temas, transcrição); sem descrição/transcrição o "por que apareceu" não tem trecho real. +- C192 (soft) — mecanismo entregue e em produção; pista de reuso, não pré-requisito. + +## Fora de escopo + +- Busca por tema no acervo interno de falas — já é C192. +- Embeddings/pgvector e infra vetorial. +- Curadoria manual de sinônimos/ontologia. +- Busca por voz. +- Analytics de busca (termos que falham, cliques) — outro item se houver demanda. +- Busca global no site inteiro ou em outros corpora (posts, notícias). + +## Rabbit holes de produto + +- **Índice vetorial/infra nova.** Se alguém "só completar": pipeline de embedding, backfill, storage vetorial, sync. **Corte neste item:** reusar o caminho lexical do C192; cobertura/mecanismo são decisão da implementação. +- **"Sempre achar algo".** Se alguém "só completar": similaridade fraca enchendo a lista. **Corte:** vazio honesto; nunca "parecido" enganoso. +- **Curador de sinônimos/ontologia.** **Corte:** fora; vazio honesto e reformulação cobrem. +- **Acervo interno como corpus "porque é mais rico".** **Corte:** só peças publicadas da Central — anti-goal do C192 e regra de PII. + +## Questões em aberto (produto) + +- **Modo explícito ou automático?** **Opções:** A) automático no mesmo campo | B) modo visível ("Termo exato | Por tema"), exato como padrão | C) ação "buscar por tema" só quando pedida. **Recomendação:** B — o eleitor precisa saber o que pediu e por que o resultado apareceu; o padrão exato preserva o que já funciona. _(assumido — validar com produto)_ +- **Como limitar custo/abuso numa página sem login?** **Opções:** A) limitador anônimo (IP/sessão) + degradação sob abuso | B) cachear a expansão e limitar por sessão | C) desafio de interação humana antes do modo. **Recomendação:** A + cache da expansão quando barato — degradar em vez de errar; o mecanismo exato fica na implementação. _(assumido — validar com produto)_ +- **Como o resultado sinaliza "por tema"?** **Opções:** A) selo "Tema" por resultado + trecho real | B) aviso único no topo | C) só o modo ativo no campo. **Recomendação:** A — proveniência por peça sustenta a confiança; o modo no campo complementa. _(assumido — validar com produto)_ +- **E se o mecanismo falhar/limite estourar?** **Opções:** A) degrada para termo exato com aviso discreto | B) erro pedindo nova tentativa | C) esconde o modo. **Recomendação:** A — nunca erro na cara nem resultado fantasma; o aviso mantém a honestidade. _(assumido — validar com produto)_ + +## Referências + +- Design UI (gate): `docs/plans/central-conteudos-busca-semantica-ui-design.html` (+ assets em `central-conteudos-busca-semantica-ui-design-assets/`) +- Precedente C192: `docs/plans/acervo-busca-semantica.md` e `docs/plans/acervo-busca-semantica-impl.md` +- Planos irmãos: `docs/plans/central-conteudos-publica.md` (S27) · `docs/plans/central-conteudos-ingestao.md` (C211) +- Arquivos-pista: `src/utilities/ai/expandSpeechSearchTheme.ts`, `src/lib/speechThemeTerms.ts`, `src/utilities/ai/rateLimit.ts`, `src/utilities/speech/speechListFilters.ts`, `src/utilities/speech/speechListUrl.ts`, `src/lib/speechSearch.ts`, `src/components/campaign/speech/SpeechResultCard.tsx`, `src/components/campaign/speech/SpeechThemeFallbackNotice.tsx`, `scripts/lib/e2e-affected-manifest.mjs` +- `AGENTS-public.md` — convenções da rota pública (visibilidade fail-closed, cache/revalidação) + +## Self-score + +5/5 — um outcome verificável (achar por sentido com proveniência e degradação honesta) dentro do appetite; persona/job/aceite sem jargão; direção no codebase é hipótese com o reuso do C192 e a diferença da rota pública explícita; nenhuma decisão dura de engenharia (limite de uso e forma do corpus ficam na implementação). diff --git a/docs/plans/central-conteudos-ingestao-ui-design.html b/docs/plans/central-conteudos-ingestao-ui-design.html new file mode 100644 index 00000000..fdf9ad48 --- /dev/null +++ b/docs/plans/central-conteudos-ingestao-ui-design.html @@ -0,0 +1,536 @@ + + + + + + + Design — C211 · Central interna + + + +
+
+ C211 · revisão do gate +

Receber, revisar, publicar

+

+ A mesa foi reduzida ao essencial: estado da peça, estado editorial e a próxima ação. + Arquivo e link entram no mesmo fluxo de catalogação. +

+
+ +
+
+ CENA 01 +

Desktop 1280 · lista compacta e respirada

+
+
+
+ +
+
+
+

Conteúdos

+

+ Peças que alimentam a Central pública. +

+
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PeçaProcessamentoPublicaçãoPróxima ação
+
+
NEEDS ASSET
+
+ Fim da escala 6×1 é saúde +

+ Vídeo · Salvador · 02:14 +

+
+
+
ProntoPublicado
+ Visita ao posto de saúde +

Vídeo enviado

+
+ Processando +

Transcrevendo…

+
Rascunho
+ Mensagem para lideranças +

Áudio preservado

+
FalhouRascunho + +
+
+

+ Rascunhos não aparecem no site. Uma falha não interrompe as outras peças. +

+
+
+
+
+ +
+
+ CENA 02 +

Desktop 1280 · lote com progresso por arquivo

+
+
+
+
+

Enviar peças

+

+ Cada arquivo vira um rascunho independente. +

+
+
+ Selecionar arquivos +

Vídeo, foto, áudio, texto ou card

+
+
+
+
+
fala-sus.mp468%
+
+
+
+
+
+ card-feira.pngEnviado +
+
+
+ audio-grupo.wav +

Falhou; os outros continuam.

+
+ +
+
+
+ +
+
+
+
+ +
+
+ CENA 03 +

Desktop 1280 · link com mídia extraída pelo caminho oficial

+
+
+
+

Adicionar por link

+

+ Instagram ou YouTube. Conteúdo próprio é extraído somente quando a plataforma oferece + caminho oficial. +

+ +
+ Sem scraping.
Se não houver acesso oficial à + mídia, a peça continua pelo link e o arquivo original pode ser anexado. +
+
+
+

O que acontece depois

+
+
+ 1 +
+ Mídia encontrada na conta oficial +

+ O arquivo entra na peça. Origem e link permanecem visíveis. +

+
+ Extraída +
+
+ 2 +
+ Mesmo processamento do upload +

+ Transcrição, título, descrição, temas e territórios são preparados para revisão. +

+
+ Processando +
+
+ ↳ +
+ Quando não há caminho oficial +

+ Peça-link criada. A assessoria pode anexar o arquivo original; mídia de terceiro + não é baixada. +

+ +
+ Peça-link +
+
+
+
+
+ +
+
+ CENA 04 +

Desktop 1280 · ficha editável e um próximo passo

+
+
+
+
+ ← Conteúdos +

Fim da escala 6×1 é saúde

+
+ ProntoRascunho +
+
+ +
+
+
+
NEEDS ASSET · PREVIEW REAL
+
+
+
Origem
+
Instagram · mídia extraída
+
+
+
Duração
+
02:14
+
+
+
+

QUANDO PUBLICADO

+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ CENAS 05–06 +

Mobile 390 · lista e link em processamento

+
+
+
+
+ Conteúdos +
+
+ +
+
+
+ Fim da escala 6×1 é saúdePronto +
+

Vídeo · Publicado

+ +
+
+
+ Visita ao postoProcessando +
+
+
+
+

Transcrevendo e catalogando…

+
+
+
+ Mensagem para liderançasFalhou +
+ +
+
+
+
+
+
+ ←Peça adicionada por link +
+
+
NEEDS ASSET · POSTER EXTRAÍDO
+
+ ProcessandoInstagram · conta oficial +
+

Preparando a peça

+
+
+
+ Arquivo extraídoConcluído +
+
+
+
+
+ Transcrição e catalogaçãoEm andamento +
+
+
+
+
+
+
+ A peça nasce como rascunho. Revise título, descrição e transcrição antes de + publicar. +
+ +
+
+
+
+
+ + diff --git a/docs/plans/central-conteudos-ingestao.md b/docs/plans/central-conteudos-ingestao.md new file mode 100644 index 00000000..a5a45a92 --- /dev/null +++ b/docs/plans/central-conteudos-ingestao.md @@ -0,0 +1,123 @@ +# C211 — Central de Conteúdos — enviar, transcrever e catalogar as peças de campanha (interno) + +Status: rascunho +Atualizado em: 2026-09-22 +Issue: #1254 +Priority: P1 +Impeccable: C — fluxo novo na vertical `/campanha/comunicacao` +Design UI: docs/plans/central-conteudos-ingestao-ui-design.html +Appetite: ~2–3 dias eng; um outcome verificável — a assessoria sobe um lote de peças (ou cola um link) e cada peça sai catalogada, transcriada e com estado de publicação +Responsável: — + +## Intenção + +A campanha "Peça voto pra Solla 1313" vai ter uma página pública com todo o material — Reels, textos, fotos, jingles, cards. Mas o material de campanha vive hoje em pastas de celular, grupos e drives: ninguém sabe o que já existe, nada é encontrável por assunto e a peça vira garimpo manual na hora de publicar. + +Este item é o lado interno: a assessoria envia peças em lote (ou cola um link do Instagram/YouTube), e cada peça é transcrita, catalogada com o máximo de detalhes e depois publicada/despublicada com um gesto. Peça que entra por link tem a mídia extraída e catalogada quando a plataforma oferecer caminho oficial; onde não houver, ela circula pelo link e a assessoria pode anexar o arquivo original. A página pública é o S27 e a busca semântica pública é o S28 — este item entrega o material catalogado que os dois vão consumir. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`, "Assessor de Comunicação"), na mesa, recebendo muitas peças por dia de gente diferente; `coordinator`/`candidate` também usam. `advisor`/`leader` não veem nada (fail-closed). +- **Job principal:** subir o material da campanha de uma vez e deixá-lo catalogado o bastante para a peça certa ser encontrada e publicada. +- **Fluxo desejado:** abre `/campanha/comunicacao/conteudos` → "Enviar peças" (vários arquivos de uma vez) ou "Adicionar por link" (Instagram/YouTube; a mídia é extraída quando houver caminho oficial) → cada peça tem estado visível → ao ficar "Pronto", a peça já vem com título, descrição, tipo, temas, cidade, região, instituição, data, duração e transcrição/texto → a assessoria revisa e edita o que quiser → "Publicar" quando for a hora; "Despublicar" tira da Central na hora, sem apagar o arquivo → se "Falhou", "Reprocessar". +- **Anti-goals de produto:** não é editor de vídeo nem estúdio de card; não duplica peça que já tem dono no site (jingle/artigo); não espelha o Instagram sozinho; não é dashboard de vaidade; não apaga arquivo em silêncio ao despublicar. + +### Esboço de fluxo (C) + +```text +[/campanha/comunicacao/conteudos] + → "Enviar peças": N arquivos de uma vez (ou "Adicionar por link" Instagram/YouTube + — a mídia é extraída e catalogada quando houver caminho oficial; senão, peça-link) + → uma peça por arquivo; estados por peça (Processando → Pronto | Falhou) + → Pronto: catalogação automática preenche os campos; assessoria revisa e edita tudo + → "Publicar" (entra na Central pública) | "Rascunho" (fora) + → "Despublicar" tira da Central na hora e preserva o arquivo + → Falhou: "Reprocessar" (uma peça não derruba as outras) +[outcome: acervo de peças de campanha catalogado e publicável, sem garimpo] +``` + +### Design UI (C) + +- Design UI (gate): `docs/plans/central-conteudos-ingestao-ui-design.html` — lista com estados, envio em lote, adicionar por link, ficha da peça (catalogação editável) e publicação, na linguagem visual do `/campanha`. + +## Objetivo e aceite + +- `communicator` — e `coordinator`/`candidate` — opera a Central; `advisor`/`leader` negados (fail-closed). +- Envio em lote: vários arquivos numa ação → uma peça por arquivo; falha de um não derruba os outros e cada peça tem estado próprio ("Processando" | "Pronto" | "Falhou"). +- Vídeo e Áudio saem com transcrição; Texto sai com o texto extraído; Foto e Card não exigem transcrição. +- Catalogação automática é ponto de partida: título, descrição, tipo, temas, cidade, região, instituição, data, duração e transcrição/texto sempre editáveis pela assessoria. +- Adicionar por link (Instagram/YouTube) cria a peça e, quando a plataforma oferecer caminho oficial de acesso à mídia (ex.: API do Instagram para a própria conta), o arquivo é extraído e passa pelo mesmo pipeline de transcrição/catalogação; sem caminho oficial, a peça circula pelo link e a assessoria pode anexar o arquivo original. +- "Rascunho" fica fora da Central pública; "Publicado" aparece; despublicar tira na hora e preserva o arquivo; "Falhou" permite "Reprocessar". +- **Guardrails:** extração só por caminhos oficiais, nunca scraping/contorno (a varredura automática é investigada no C212); sem PII de eleitor; sem disparo em massa; acervo de falas e cortes só entram se a assessoria adicionar manualmente como peça; sem segundo cadastro de pessoa. + +## Dados (intenção) + +- **Vou apresentar dados?** Sim, só derivado — a catalogação (metadados + transcrição/texto) é dado estruturado consumido por S27/S28 e, depois, pelo C213; este item não apresenta agregado nem KPI. +- **Decisões desbloqueadas:** N/A — a escolha da assessoria é editorial ("qual peça publicar/despublicar"), não numérica. +- **Forma:** N/A — restrição de produto: sem contadores de vaidade (views/curtidas) e sem score de busca exposto na tela. + +## Dados da decisão (literais) + +- **Rota interna:** `/campanha/comunicacao/conteudos`; sub-item "Conteúdos" na nav de Comunicação. +- **Papel:** `communicator` = "Assessor de Comunicação"; `coordinator`/`candidate` também; `advisor`/`leader` negados (gate de comunicação, fail-closed). +- **Tipos de peça:** "Vídeo" | "Foto" | "Texto" | "Áudio" | "Card". +- **Publicação:** "Rascunho" | "Publicado" — despublicar tira da Central na hora, arquivo preservado. +- **Processamento:** "Processando" | "Pronto" | "Falhou" (com "Reprocessar"). +- **Envio em lote:** vários arquivos numa vez → uma peça por arquivo; falha de um não derruba os outros. +- **Catalogação automática (revisável):** título, descrição, tipo, temas, cidade, região, instituição, data, duração, transcrição/texto. +- **Adicionar por link:** Instagram/YouTube (colar link) — a peça entra com a mídia extraída e catalogada quando houver caminho oficial; sem caminho oficial, circula pelo link e o arquivo pode ser anexado pela assessoria. Mídia de terceiro nunca é baixada. +- **Varredura automática do Instagram:** investigação aprovada no gate → **C212** (viabilidade com API oficial × scraping; o C211 aplica o mecanismo que ela recomendar). Scraping não é mecanismo — nem no C211 nem no C212. +- **Acervo de falas e cortes:** fora por produto; entram só se a assessoria adicionar manualmente como peça. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/app/(campaign)/campanha/(app)/comunicacao/conteudos/`, `src/components/campaign//`, `src/utilities//`, `src/collections/`, `src/lib/campaignPaths.ts` + `src/components/campaign/shell/nav.ts`. +- **Precedente a olhar:** C199 (`src/collections/Recording*.ts`, `src/utilities/recordings/recordingUpload.ts|recordingJob.ts|recordingScheduler.ts`, rota `.../acervo/gravacoes/enviar/route.ts`, estados em `src/lib/recording.ts`, retry em `src/app/(campaign)/campanha/actions/recording.ts`); catalogação (`speechClassifier.ts`, `speechCutMetadata.ts`, taxonomias em `src/lib/speechFacets.ts|municipalityCatalog.ts|bahiaTerritories.ts|institutionCatalog.ts`); kill switch + revalidação (`Jingle.ts`, `src/utilities/documents.ts`, `jingleReads.ts`); listas (`CampaignTable.tsx`, `CampaignListOmnibox.tsx`, `campaignListUrl.ts`); feeds oficiais (`SocialFeedSettings`, `instagramFeed.ts`, `youtubeFeed.ts`) — hoje não há fetch por link (oEmbed), só listagem do perfil. +- **Risco de acoplamento:** (1) não existe upload em lote no app — o job roda via `after()` no mesmo processo, então N arquivos = N jobs concorrentes (o lote precisa de política própria; decisão do plano de implementação); (2) mídia da peça publicada vs mídia privada do C199/C193 — respeitar o dono de cada mecanismo, sem segunda cópia de arquivo que já tem dono; coleção de upload nova precisa entrar na lista do plugin S3; (3) sub-item novo na nav exige serializar com itens em voo; (4) gate de comunicação já existe — não criar gate gêmeo. + +## Dependências + +- Nenhuma dura aberta — reusa C199 (upload + transcrição), C193 (mídia privada) e C194 (biblioteca interna, kill switch/revalidação) entregues. +- Soft: **C212** (investigação da varredura/extração) refina o caminho de link; S27 (página pública) e S28 (busca semântica) consomem este item; C213 (analytics) vem depois. Não invadir esses escopos. + +## Fora de escopo + +- Página pública da Central (S27) e busca semântica pública (S28). +- Analytics de consumo (C213). +- Scraping/varredura do perfil do Instagram — a viabilidade é o C212; a implementação, se aprovada, é item próprio. +- Download/espelho de mídia de terceiro (só a própria conta, por caminho oficial). +- Editor de vídeo, gerador de card personalizável e edição de mídia. +- Ingestão automática do acervo de falas/cortes. +- Aprovação editorial multi-etapas e fluxo de revisão com mais de um aprovador. + +## Rabbit holes de produto + +- **Scraping do Instagram.** Se alguém "só completar": crawler, login em conta, bloqueio e risco jurídico. **Corte neste item:** caminhos oficiais e link; a varredura é investigada no C212 e nunca por scraping. +- **Segundo CMS/acervo paralelo.** Se alguém "só completar": reupload de jingle/artigo que já têm dono, com duas fontes de verdade. **Corte neste item:** peça convive com o dono existente; sem cópia de arquivo que já tem dono. +- **Estúdio de criação.** Se alguém "só completar": templates, corte, legenda queimada, editor embutido. **Corte neste item:** catalogar, transcrever e publicar — criar peça é de outra ferramenta. +- **Publicação automática sem curadoria.** Se alguém "só completar": tudo que sobe já aparece no público. **Corte neste item:** "Rascunho" é o padrão e publicar é gesto explícito. +- **Infra de fila/upload genérico.** Se alguém "só completar": fila, retomada, chunking, retry global, tempo real. **Corte neste item:** lote com estado por peça e "Reprocessar". + +## Questões em aberto (produto) + +- **Varredura automática do Instagram?** **Decidido no gate:** investigar agora, via **C212** (viabilidade com a API oficial; scraping fora). O C211 mantém o link manual como caminho e aplica o mecanismo que o C212 recomendar. _(decidido)_ +- **Peça nasce "Rascunho" ou "Publicado"?** **Opções:** A) "Rascunho" por padrão, publicar é gesto explícito | B) publica no envio | C) escolher no envio. **Recomendação:** A — evita material sem revisão no ar e deixa o kill switch com lugar claro. _(assumido — validar com produto)_ +- **Peça por link: circula ou é baixada?** **Decidido no gate:** extrair e catalogar quando houver caminho oficial (conteúdo próprio); sem caminho oficial, circular pelo link. **Corte que permanece:** mídia de terceiro nunca é baixada. _(decidido — refinar no C212)_ +- **Limite do envio em lote?** **Opções:** A) limite generoso com aviso claro acima dele | B) sem limite | C) limite baixo (≈10). **Recomendação:** A — o caso real é despejo de material de um evento; o valor é decisão da implementação. _(assumido — validar com produto)_ + +## Referências + +- Design UI (gate): `docs/plans/central-conteudos-ingestao-ui-design.html` (+ assets em `central-conteudos-ingestao-ui-design-assets/`) +- Planos irmãos: `docs/plans/acervo-gravacoes-enviadas.md` (C199) · `docs/plans/reels-reel-privado.md` (C193) · `docs/plans/reels-biblioteca.md` (C194) · `docs/plans/central-conteudos-publica.md` (S27) · `docs/plans/central-conteudos-busca-semantica.md` (S28) · `docs/plans/central-conteudos-varredura-instagram.md` (C212) +- Arquivos-pista: `src/collections/Recording.ts` · `src/collections/RecordingMedia.ts` · `src/utilities/recordings/recordingUpload.ts` · `src/utilities/recordings/recordingJob.ts` · `src/utilities/recordings/recordingScheduler.ts` · `src/lib/recording.ts` · `src/utilities/speech/speechClassifier.ts` · `src/utilities/speech/speechCutMetadata.ts` · `src/collections/Jingle.ts` · `src/globals/SocialFeedSettings.ts` · `src/utilities/socialFeed/instagramFeed.ts` · `src/utilities/socialFeed/youtubeFeed.ts` · `src/lib/campaignPaths.ts` · `src/components/campaign/shell/nav.ts` · `src/lib/campaignRoles.ts` · `src/utilities/campaignPageActor.ts` +- `AGENTS-campaign.md` — RBAC da vertical `/campanha`, comunicação interna e leader lockdown + +## Self-score (shaping) + +1. Fatia = um outcome verificável? **Sim** — lote/link entra e a peça sai catalogada e publicável. +2. Appetite declarado e a intenção cabe? **Sim** (~2–3 dias; scraping e editor cortados para fora). +3. Persona + job + aceite claros sem jargão de stack? **Sim**. +4. Direção no codebase é hipótese? **Sim** — precedentes e riscos, sem contrato técnico. +5. Zero decisões duras de engenharia no plano? **Sim** — schema, fila, limites e coleção ficam para o plano de implementação. + +**Score: 5/5.** diff --git a/docs/plans/central-conteudos-publica-ui-design.html b/docs/plans/central-conteudos-publica-ui-design.html new file mode 100644 index 00000000..5ef1f00d --- /dev/null +++ b/docs/plans/central-conteudos-publica-ui-design.html @@ -0,0 +1,499 @@ + + + + + + + Design — S27 · Peça voto pra Solla 1313 + + + +
+
+ S27 · revisão do gate +

Peça voto. Faça o 1313 chegar mais longe.

+

+ Mobile-first, direto no catálogo: ver, ouvir, baixar e compartilhar uma peça oficial sem + abrir outra página. +

+
+ +
+
+ CENA 01 +

Desktop 1280 · catálogo mais limpo, com ação no card

+
+
+
+ Jorge SollaCentral de Conteúdos +
+
+
+
+

PEÇA VOTO PRA SOLLA 1313

+

+ Uma mensagem sua pode conquistar mais um voto. +

+

+ Escolha uma peça, mande para alguém que você conhece e peça o voto no 1313. +

+
+ 1313 Deputado Federal +
+
+
+
+ +
+
+ Tipo⌄Cidade⌄Região⌄Tema⌄Instituição⌄ +
+
+
+

Escolha, compartilhe e peça voto

+

+ O play só carrega a mídia quando você pedir. +

+
+ Abra o título para ver detalhes +
+
+
+
+ NEEDS ASSET · POSTER REAL02:14 +
+
+ Vídeo +

Fim da escala 6×1 é saúde

+

Trabalho · Salvador

+
+ +
+
+
+
+
+ NEEDS ASSET · CAPA REAL DO ÁUDIO00:46 +
+
+ Áudio +

Mensagem para mandar no grupo

+

Campanha

+
+ +
+
+
+
+
+
+ 1313 Deputado Federal +

SEU NOME + SUA FOTO

+
+
+
+ Card personalizado +

Faça seu card com Solla 1313

+

Criado no seu aparelho.

+ Fazer meu card +
+
+
+
+
+
NEEDS ASSET · FOTO REAL
+
+ Foto +

Solla em defesa do SUS

+
+ +
+
+
+
+
+ “Saúde é direito.” +
+
+ Texto +

Por que defender o SUS

+
+ +
+
+
+
+
+
+ Jorge José Santos Pereira Solla · Candidato a Deputado Federal · Nº 1313 · Federação + Brasil da Esperança (PT/PCdoB/PV) · CNPJ: 68.430.467/0001-05 · Propaganda eleitoral + gratuita · Eleições 2026 · 1º turno: 04/10/2026. +
+
+
+ +
+
+ CENAS 02–03 +

Mobile 390 · antes e depois do play sob demanda

+
+
+
+
+ Jorge Solla☰ +
+
+

PEÇA VOTO PRA SOLLA 1313

+

+ Mande uma peça.
Peça mais um voto. +

+

+ Escolha alguém, compartilhe e peça o voto no 1313. +

+
+
+ +
+ Tipo⌄Cidade⌄Tema⌄ +
+
+
+ NEEDS ASSET · POSTER REAL02:14 +
+
+ Vídeo · ainda não carregado +

Fim da escala 6×1 é saúde

+

+ Toque no play para carregar só este vídeo. +

+
+ +
+ Ver detalhes da peça → +
+
+
+
+
+
+ ←Central de Conteúdos +
+
+

DEPOIS DO PLAY

+
+
+
+ NEEDS ASSET · VÍDEO EM REPRODUÇÃO +
+ +
+
+
+
+
+ 00:4902:14 +
+
+
+
+

Fim da escala 6×1 é saúde

+
+ +
+
+
+
+
+

Peça esse voto no WhatsApp

+

A mensagem é sua: revise antes de abrir.

+ +
+ +
+

+ Sem destinatário e sem envio automático. Se o aparelho não compartilhar o arquivo, + ele será baixado. +

+
+
+
+
+
+ +
+
+ CENA 04 +

Página individual · detalhes e link bonito, sem repetir o catálogo inteiro

+
+
+
+ Jorge SollaVoltar à Central +
+
+
NEEDS ASSET · PREVIEW REAL DA PEÇA
+
+ Vídeo +

Fim da escala 6×1 é saúde

+

+ Jorge Solla explica por que reduzir a jornada protege a saúde de quem trabalha. +

+
+
+
Tema
+
Trabalho e saúde
+
+
+
Local
+
Salvador
+
+
+
Duração
+
02:14
+
+
+
+ +
+
+
+
+
+ +
+
+ CENA 05 +

Estados críticos preservados · vazio, indisponível e carregando

+
+
+
+

As primeiras peças estão a caminho

+

+ Enquanto isso, faça seu card e peça voto pra Solla 1313. +

+ Fazer meu card +

Vazio · 1280/390

+
+
+

Esta peça não está disponível

+

+ Ela pode ter sido retirada. Encontre outro material oficial e continue pedindo voto. +

+ Ver outras peças +

Link despublicado · 1280/390

+
+
+
+
+
+
+
+
+
+

Carregando · 1280/390

+
+
+
+
+ + diff --git a/docs/plans/central-conteudos-publica.md b/docs/plans/central-conteudos-publica.md new file mode 100644 index 00000000..7064d89d --- /dev/null +++ b/docs/plans/central-conteudos-publica.md @@ -0,0 +1,121 @@ +# S27 — Central de Conteúdos pública — Peça voto pra Solla 1313 + +Status: rascunho +Atualizado em: 2026-09-22 +Issue: #1255 +Priority: P1 +Impeccable: C — fluxo público novo (`/conteudos` + página da peça) +Design UI: docs/plans/central-conteudos-publica-ui-design.html +Appetite: ~2–3 dias eng; a Central no ar com as peças de C211 filtráveis, cada peça com página própria e compartilhamento contextual de voto +Responsável: — + +## Intenção + +Estamos na reta final — 1º turno em 4 de outubro — e o maior cabo eleitoral de Solla é o próprio eleitor: quem já vota precisa pedir voto. Hoje o material (Reels, textos, fotos, jingles, cards) está espalhado entre grupo de WhatsApp, drive e redes, e quem quer ajudar não sabe onde pegar a peça certa nem o que escrever junto. Esta fatia cria a campanha "Peça voto pra Solla 1313" com uma casa para o material: a Central de Conteúdos. O eleitor chega, filtra pelo que faz sentido para a sua cidade/região/tema, vê e ouve a peça direto no catálogo (play sob demanda) e baixa ou compartilha dali mesmo no WhatsApp, com uma mensagem que já pede voto — contextualizada pela peça. Entre as peças, a criação do card personalizado aparece como uma peça do catálogo, que leva ao estúdio. A chamada e o CTA da tela têm um objetivo único: fazer o visitante pedir voto pro Solla 1313 — apelativos e verificáveis. E a Central não dispara nada: ela empodera o eleitor a fazer, no aparelho dele, o que a campanha não pode fazer em massa. + +## Persona e fluxo + +- **Persona / contexto:** eleitor/simpatizante/liderança no celular, com pressa, no meio da rotina; quer repassar material de Solla e não sabe o que escrever nem onde achar a peça certa. +- **Job principal:** pegar uma peça oficial de Solla e pedir voto pra ele no WhatsApp, sem trabalho e sem medo de errar. +- **Fluxo desejado:** abre `/conteudos` → vê "Peça voto pra Solla 1313 · Central de Conteúdos" → filtra por Tipo/Cidade/Região/Tema/Instituição ou busca por termo → vê a peça no próprio catálogo (vídeo/áudio só carrega ao tocar em play; foto com preview leve) → baixa ou compartilha dali mesmo (mensagem de voto sugerida, editável) → repassa; se quiser o card dele, toca na peça de card e cai no `/cards`. +- **Anti-goals de produto:** não vira rede social (sem comentários/likes/perfil); não vira editor de mídia nem segundo catálogo (quem cataloga é o interno, C211); não captura dado nem pede login; não dispara em massa (nada de WhatsApp Business API); não re-hospeda o que já tem dono (jingle/artigo/card). + +### Esboço de fluxo (C) + +```text +[eleitor no celular] → /conteudos ("Peça voto pra Solla 1313 · Central de Conteúdos") +→ filtra (Tipo · Cidade · Região · Tema · Instituição) e/ou busca por termo +→ vê/ouve a peça no catálogo (play sob demanda; foto com preview leve) +→ Baixar · Compartilhar (mensagem de voto no WhatsApp · a mídia · copiar link) dali mesmo + · peça de Card → /cards (fazer o meu) +→ [eleitor edita e envia no próprio WhatsApp] → a peça circula +→ /conteudos/ continua existindo para detalhes e para o link abrir bonito +[peça despublicada] → some da lista; link direto mostra estado honesto de indisponível +``` + +### Design UI (C) + +- Design UI (gate): `docs/plans/central-conteudos-publica-ui-design.html` — classe C porque é fluxo público novo (catálogo filtrável com preview/ações + página da peça); o design hi-fi é obrigatório no gate. Revisão pedida no gate: layout mais limpo e copy focada em pedir voto. + +## Objetivo e aceite + +- O visitante abre `/conteudos` e vê as peças publicadas (as de C211), filtráveis por Tipo · Cidade · Região · Tema · Instituição e por termo de busca; os filtros combinam entre si. +- Cada peça tem página própria `/conteudos/` com preview (título + imagem) para o link abrir bem no WhatsApp. +- Preview no próprio catálogo: Vídeo e Áudio só carregam quando o eleitor toca em play (nada de baixar tudo de uma vez); Foto aparece com preview leve; as ações `Baixar` e `Compartilhar` (Mensagem no WhatsApp · A mídia · Copiar link) funcionam direto do card, sem precisar abrir a peça. +- A criação do card personalizado aparece no catálogo como uma peça (mesmo grid), que leva ao estúdio `/cards` para o eleitor fazer o dele. +- A chamada e o CTA da página pedem voto (apelativos, sem promessa irrealista) — o objetivo único da tela é o eleitor pedir voto pro Solla 1313. +- Ações por peça: `Baixar` · `Compartilhar` (opções: "Mensagem no WhatsApp" com a mensagem de voto sugerida e editável · "A mídia" · "Copiar link") · `Fazer meu card` (peça de Card → `/cards`). +- "A mídia": onde o aparelho permitir, abre a folha de compartilhamento nativa com o arquivo (o eleitor escolhe o WhatsApp); onde não houver, baixa — nunca fingir que anexou. `wa.me` não anexa arquivo; o link é sempre a alternativa que funciona em qualquer aparelho. +- Peça-link (Instagram/YouTube) compartilha pelo link da plataforma; peça com arquivo permite baixar e compartilhar pelo link da peça — sem segunda cópia. +- O compartilhamento é o eleitor no próprio aparelho: `wa.me/?text=`, sem destinatário e sem envio pelo sistema; a mensagem nunca sai sozinha. +- Mobile-first e leve: usável em conexão ruim, sem login e sem cadastro. +- **Kill switch:** despublicar uma peça a tira da Central e da própria página na hora; sem peça publicada, a Central mostra estado honesto e o link de descoberta some. +- **Guardrails:** LGPD — sem login, sem captura de dado, sem PII e sem rastreio neste item (analytics = C213); TSE — nenhuma promessa irrealista, identidade eleitoral visível (bloco obrigatório do rodapé preservado), nada de disparo em massa; cards seguem 100% no aparelho (a Central só convida para `/cards`); nenhuma mídia de terceiro baixada; o link do Instagram/YouTube da peça nunca deixa a Central parecer fonte oficial da plataforma. + +## Dados (intenção) + +- **Dados: N/A** — a Central não apresenta número, contador nem ranking; é superfície de peças. Quem mede circulação é C213 (fora de escopo). +- **Decisões desbloqueadas:** o eleitor decide o que baixar/compartilhar; a comunicação decide o que publicar/despublicar. Nenhum dado do visitante é coletado. + +## Dados da decisão (literais) + +- Nome na tela: `Central de Conteúdos`; chamada principal: `Peça voto pra Solla 1313` — chamada e CTA de pedido de voto, apelativos e verificáveis. +- URL (decidida no gate): lista `/conteudos`; peça `/conteudos/`; `conteudos` entra nos slugs reservados do site. +- Filtros (rótulos): `Tipo` · `Cidade` · `Região` · `Tema` · `Instituição`; mais campo de busca por termo (busca semântica é S28). +- Ações por peça (no card do catálogo e na página): `Baixar` · `Compartilhar` com as opções `Mensagem no WhatsApp` · `A mídia` · `Copiar link`; a peça de Card leva a `Fazer meu card` → `/cards`. +- Preview: Vídeo e Áudio com play sob demanda (a mídia só é buscada no toque, sem baixar tudo); Foto com preview leve; a página da peça continua existindo para detalhes e para o link abrir bonito. +- Mensagens de voto (assumidas — validar com a comunicação), sempre editáveis, com o sistema nunca enviando: + - Vídeo → `Estamos na reta final e o Jorge Solla 1313 precisa do seu voto. Olha esse vídeo: — . Peça voto pra Solla 1313 pra quem você conhece.` + - Áudio → `Ouça e mande pro grupo: — . Peça voto pra Solla 1313.` + - Foto/Texto/Card → `Fiz/achei esse material do Solla 1313: — . Peça voto pra Solla 1313 também.` +- O sistema nunca envia: abre o WhatsApp com o texto pronto e o eleitor edita antes de mandar (`wa.me/?text=`, sem destinatário). +- Peça-link (Instagram/YouTube) compartilha pelo link; peça-arquivo permite `Baixar`, `A mídia` (folha nativa quando houver, senão download) e compartilhar pelo link da peça — sem re-hospedar cópia. +- Toda peça publicada tem página própria com preview `título + imagem` (OG) para o link abrir bem no WhatsApp. +- Kill switch por peça (publicado/despublicado) — despublicar tira na hora, sem apagar arquivo. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** rota nova `src/app/(frontend)/conteudos/` (lista + `[slug]`); filtros/busca e card em `src/components/`; share reusando `src/lib/contentShare.ts`, `src/lib/phone.ts` (`buildWhatsAppTextShareUrl`), `ContentShareButton`/`CopyLinkButton` e o padrão de "copiar com feedback"; cache e revalidação no padrão de `src/utilities/documents.ts` + allowlist em `src/app/(frontend)/api/revalidate/route.ts`; descoberta em `src/components/CampaignFooter.tsx`/`SiteHeader.tsx`. +- **Precedente a olhar:** `/jingles` (página pública com kill switch + ``), `/corte/[id]` (página pública de peça + share kit), `ShareLink` (OG + `published` como kill switch), `CardsStudio` (`/cards` com deep-link `?model=`), S4 (`docs/plans/compartilhar-conteudos-home-whatsapp.md`). +- **Risco de acoplamento:** rota estática nova precisa entrar em `SHARE_LINK_RESERVED_SLUGS` (`src/lib/shareLink.ts`) senão o drift test falha; mídia pública baixa por atributo `download` (proxy `/api/media/file/...` sem `Content-Disposition`) — sem zip/lote; cards personalizáveis são canvas client-side (blob sem URL pública) → só convite para `/cards`; não existe precedente de filtro/busca pública (o maquinário de URL state é interno) — seguir o padrão do site, sem importar o interno; a folha nativa de compartilhamento com arquivo (`navigator.share`) é suportada só em parte dos aparelhos — sempre com fallback de download; o preview de vídeo/áudio no catálogo exige carregamento sob demanda (poster + play) para a página não pesar. + +## Dependências + +- **C211** (peças catalogadas e publicadas pelo interno) — dura: sem catálogo publicado não há Central. +- Design hi-fi aprovado no gate. + +## Fora de escopo + +- Busca semântica (S28) — aqui é busca por termo. +- Analytics, contadores, UTM e qualquer rastreio do visitante (C213). +- Editar/subir mídia pela Central (é C211); comentários/likes/perfil; app de disparo ou integração com WhatsApp Business API. +- Segunda cópia de arquivo (re-hospedar jingle/artigo/card); download em zip/lote. +- Página de bandeira/SEO §7.2 (`docs/campanha/plano-site-campanha-2026.md` §7.2) — peça não vira landing de bandeira; redesign do shell/nav/home. + +## Rabbit holes de produto + +- **Uma tela por tipo de mídia.** Se alguém "só completar": player de áudio, lightbox de foto, embed de IG, cada tipo com layout próprio. **Corte neste item:** um board único com card por peça; tipo é dado do filtro, não tela. +- **Catálogo virar cabine de mídia.** Se alguém "só completar": carregar todos os vídeos/áudios na abertura, autoplay, player próprio. **Corte neste item:** play sob demanda (a mídia só carrega no toque) e nenhum recurso além de dar play/ouvir. +- **A Central virar rede social.** Se alguém "só completar": curtir, comentar, salvar, perfil, feed. **Corte:** nada de UGC/engajamento — só encontrar, baixar e repassar. +- **Re-hospedar o acervo inteiro.** Se alguém "só completar": subir jingle/artigo/card em cópia própria na Central. **Corte:** a Central referencia o dono; só a peça que nasce nela ganha arquivo. +- **Disparo em massa "para ajudar".** Se alguém "só completar": lista, agendamento, API Business. **Corte:** `wa.me` do eleitor, sem destinatário — vedação TSE. +- **Personalizador embutido na Central.** Se alguém "só completar": renderizar o card no servidor para "baixar pronto". **Corte:** a peça de card leva a `/cards`; o card do eleitor segue 100% no aparelho. + +## Questões em aberto (produto) + +- **URL `/conteudos` + `/conteudos/`?** **Decidido no gate:** A — lista e peça no mesmo namespace; entra em `SHARE_LINK_RESERVED_SLUGS`. _(decidido)_ +- **Chamada/CTA da página?** **Decidido no gate:** foco em pedir voto ("Peça voto pra Solla 1313"), apelativo e verificável; a copy final passa pela comunicação. _(decidido)_ +- **Mensagem sugerida por tipo?** **Opções:** A) os 3 templates (Vídeo/Áudio/Foto-Texto-Card) dos literais | B) um template único | C) só o link, sem sugestão. **Recomendação:** A — é o pedido do dono; sempre editável antes de enviar. _(assumido — validar com a comunicação)_ +- **Como a mídia circula?** **Opções:** A) peça-link compartilha pelo link da plataforma; peça-arquivo oferece "A mídia" (folha nativa com o arquivo, quando suportada) e `Baixar` como fallback | B) tudo pelo link da peça | C) só baixar e o eleitor anexa. **Recomendação:** A — é o pedido do dono (compartilhar a mídia diretamente), com fallback honesto onde o aparelho não suportar; `wa.me` não anexa arquivo. _(assumido)_ +- **Filtros v1?** **Opções:** A) os 5 rótulos + busca por termo | B) só `Tipo` + `Cidade` + busca | C) só busca. **Recomendação:** A, exibindo apenas filtro que tenha valor entre as peças publicadas. _(assumido — validar com produto)_ + +## Referências + +- Design UI (gate): `docs/plans/central-conteudos-publica-ui-design.html` (+ assets em `central-conteudos-publica-ui-design-assets/`) +- Planos irmãos: `docs/plans/central-conteudos-ingestao.md` (C211 — o catálogo que alimenta a página), `docs/plans/compartilhar-conteudos-home-whatsapp.md` (S4 — wa.me do remetente, sem telemetria), `docs/plans/links-compartilhamento-miniatura-og.md` (S19), `docs/plans/cards-personalizados-campanha.md` (S13), `docs/plans/corte-pagina-publica-design.md` (C167). +- Arquivos-pista: `src/lib/contentShare.ts`, `src/components/ContentShareButton.tsx`, `src/lib/phone.ts`, `src/lib/shareLink.ts`, `src/components/jingles/JingleCards.tsx`, `src/components/cards/CardsStudio.tsx`, `src/components/CampaignFooter.tsx`, `src/utilities/documents.ts`, `src/app/(frontend)/api/revalidate/route.ts`. +- `AGENTS-public.md` — convenções do site público; `docs/campanha/plano-site-campanha-2026.md` §7.1 (compartilhamento por seção — ideia do cliente). + +## Self-score (shaping) + +5/5 — (1) fatia = um outcome verificável (Central no ar com peças filtráveis e compartilhamento de voto); (2) appetite ~2–3 dias cabe com design hi-fi + port; (3) persona/job/aceite em linguagem de produto; (4) direção no codebase é hipótese; (5) zero decisão dura de engenharia. diff --git a/docs/plans/central-conteudos-varredura-instagram.md b/docs/plans/central-conteudos-varredura-instagram.md new file mode 100644 index 00000000..ca5aa4e0 --- /dev/null +++ b/docs/plans/central-conteudos-varredura-instagram.md @@ -0,0 +1,97 @@ +# C212 — Central de Conteúdos — viabilidade da varredura automática do Instagram (e da extração de mídia por link) + +Status: rascunho +Atualizado em: 2026-09-22 +Issue: #1256 +Priority: P2 +Impeccable: A — N/A sem UI +Design UI: N/A — sem UI +Appetite: ~0,5–1 dia eng; um outcome verificável — as quatro perguntas respondidas com evidência (repo + docs oficiais) e uma recomendação de mecanismo, limites e cortes, sem implementar +Responsável: — + +## Intenção + +No gate do C211 o dono decidiu duas coisas: peça adicionada por link entra com a mídia extraída e catalogada, não só com o link; e, sobre a ingestão do Instagram, "investigar varredura automática agora". A eleição é 04/10 e a Central (C211/S27) ainda vai nascer — se a varredura for viável, ela muda o desenho da ingestão antes de existir; se não for, o C211 precisa saber com evidência, não por precaução genérica. + +O Teqo já tem integração oficial com a Graph API do Instagram (feed da home, S11) e com a YouTube Data API v3 (S2). O que falta saber é se esses mesmos caminhos oficiais bastam para a Central catalogar/transcrever mídia, o que exatamente eles não entregam e a que custo (limites, token, curadoria). Este item entrega a investigação com evidência e recomendação; a implementação (se aprovada) vira item próprio. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`) que vai operar a Central; e quem decide produto/engenharia (`coordinator`/`candidate` e o dono no gate). +- **Job principal:** saber, com evidência, se a varredura automática do perfil e a extração de mídia por link são viáveis e sob quais limites — para decidir o que implementar no C211. +- **Fluxo desejado:** pergunta → evidência (o que o repo já faz + docs oficiais datadas) → recomendação (mecanismo, limites, o que fica de fora, próximo item) → decisão no gate. +- **Anti-goals de produto:** não é a implementação da varredura nem da extração; não vira spike de scraping; não redesenha o feed da home; não cria tela; não promete o que não é verificável. + +## Objetivo e aceite + +- **Q1 — a Graph API oficial já integrada entrega as mídias recentes do perfil do Solla com metadados e `media_url` suficientes para catalogar/transcrever?** Resposta com campos, paginação, rate limit, validade/refresh do token e periodicidade segura, citando o que a integração atual pede e o que descarta (`src/utilities/socialFeed/instagramFeed.ts`) + docs oficiais. Limite/expiração que não se confirmar na doc: declarar **"a confirmar na implementação"** — nunca estimar. +- **Q2 — peça por link (IG/YT):** qual o caminho oficial/aceitável de extração em cada plataforma; o que NÃO é aceitável (scraping, contorno, download de mídia de terceiro); e o que fazer quando não há caminho oficial — a peça circula pelo link e a assessoria pode anexar o arquivo (refina a regra do C211). +- **Q3 — varredura automática do perfil: vale a pena?** Comparar explicitamente (A) API oficial agendada/recebida; (B) scraping; (C) sem varredura (link manual do C211) — com curadoria proposta (o que entra, rascunho, filtro por tipo/período), riscos (ToS da Meta, bloqueio de conta/IP, jurídico/reputacional, fragilidade) e custo operacional. +- **Q4 — recomendação final:** mecanismo, limites, o que fica de fora e o item de implementação que nasceria daí (descrito, não criado). +- **Registro:** os achados ficam anexados a este plano (seção de achados, com links oficiais datados) — o entregável é decisão documentada, não código. +- **Guardrails:** NUNCA scraping/contorno como mecanismo recomendado; se a conclusão for que só o scraping alcança algo desejado, a recomendação é NÃO fazer e dizer o que se perde. Nada entra na Central pública sem curadoria (rascunho → publicado). Sem PII; sem credencial em log. A investigação não altera comportamento de produção (feed da home intocado); evidência = repo + docs oficiais, com probe na API real só leitura, se necessário. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — não há superfície de dados: o resultado é decisão documentada (evidência citada + recomendação), não métrica ou agregado para usuário. +- **Decisões desbloqueadas:** N/A — a decisão é do gate (dono), a partir da recomendação. +- **Forma:** N/A. + +## Dados da decisão (literais) + +- **Decisão do dono no gate (verbatim):** "Quando o assessor adiciona uma peça por link do Instagram ou Youtube, a mídia deve ser automaticamente extraída e catalogada."; e "Investigar varredura automática agora". +- Peça por link entra com a mídia extraída e catalogada **quando houver caminho oficial**; sem caminho oficial, a peça circula pelo link e a assessoria pode anexar o arquivo (isto é o C211; aqui só se refina). +- **NUNCA scraping/contorno de plataforma como mecanismo recomendado**; se a investigação concluir que scraping é a única via para algo desejado, a recomendação é NÃO fazer e dizer o que se perde. +- **Curadoria:** nada entra na Central pública sem passar pela assessoria ("Rascunho" → "Publicado" — regra do C211). +- **Nada de PII; nada de credencial em log.** +- **Escopo de plataformas:** Instagram (`@depjorgesolla`, conta Business/Creator) e YouTube (canal oficial `@JorgeSollaDep`) — demais redes fora. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/utilities/socialFeed/` (`instagramFeed.ts`, `instagramFeedView.ts`, `instagramSync.ts`, `youtubeFeed.ts`), `src/globals/SocialFeedSettings.ts`, `src/lib/speechVod.ts` (parse de link de YouTube já existente) e o runbook `docs/ops/instagram-feed-token-runbook.md`; a Central é o C211. +- **Fatos já verificados no repo (ponto de partida, a revalidar):** a integração pede `id,caption,media_type,media_url,permalink,thumbnail_url,timestamp,children{...}` em `GET /{userId}/media` (`instagramFeed.ts:94`) — o `media_url` chega, mas hoje é descartado no parse (vira thumbnail, `instagramFeed.ts:111`); `limit` é capado em 50 (`instagramFeed.ts:223`) e o sync busca `maxItems + 10` (`instagramSync.ts:103`); não há paginação (`paging.cursors.after`) nem fetch por link (grep por oEmbed = 0); o refresh é `grant_type=ig_refresh_token` (`instagramFeed.ts:237`); a YouTube Data API (`search.list`/`videos.list`) não fornece arquivo de vídeo; o feed é atualizado por render com cache de 5 min (`instagramFeedView.ts:96`) — cadência de board, não de acervo. +- **Precedente a olhar:** S3 (`docs/plans/secao-conteudos-home-instagram.md`) e o runbook do token; C199 (`src/utilities/recordings/recordingScheduler.ts`) se a varredura agendada for aprovada; C211 para o encaixe da peça-link. +- **Risco de acoplamento:** o feed da home tem contrato próprio (fail-closed, snapshot, kill switch) — a investigação não o redesenha; se a varredura usar o mesmo token/global, a proposta deve explicitar como não ampliar o escopo do board nem criar segundo estado de sync. + +## Dependências + +- **Soft: C211** — este item informa a implementação dele (ingestão por link e eventual varredura); o C211 começa sem este (link manual é o fallback). **S27 não depende.** +- Credenciais Meta/Google já existentes (token/ID IG e API key YT no `SocialFeedSettings`); a validade real do token é parte da investigação (painel de status + runbook). + +## Fora de escopo + +- Implementar a varredura (se aprovada, vira item próprio) e implementar a extração de mídia por link. +- Qualquer scraping/contorno, download de mídia de terceiro ou automação de conta. +- Mudar a integração do feed da home (S3) ou o board público. +- Criar UI nova (o resultado é decisão documentada; a UI da Central é do C211). +- Transcrição/embeddings (C211/S28) e analytics (C213). + +## Rabbit holes de produto + +- **"Investigar virou implementar".** Se alguém "só completar": cria coleção, agendador, rota e migration dentro da investigação. **Corte neste item:** o entregável é evidência + recomendação; implementação é item próprio. +- **"Scraping porque a API não dá conta".** Se alguém "só completar": crawler, login em conta, contorno para pegar mídia de terceiro ou perfil fora do caminho oficial. **Corte:** nunca como recomendação; a investigação diz o que se perde e para. +- **"Cobrir todas as redes".** Se alguém "só completar": TikTok, Facebook, X, Kwai. **Corte:** escopo é Instagram + YouTube, as duas com oficialidade já decidida. +- **"Credencial/estado no lugar errado".** Se alguém "só completar": token em arquivo/log, cursor de varredura em memória, mídia em pasta sem dono. **Corte:** credencial só no `SocialFeedSettings` (admin-only), nunca em log; estado novo tem dono definido no item de implementação. + +## Questões em aberto (produto) + +- **Se a varredura for aprovada, o que ela traz?** **Opções:** A) só as mídias recentes do perfil oficial, tudo como rascunho para a assessoria triar | B) varredura com filtro (ex.: só Reels/vídeos, janela de período) que já descarta o que não interessa | C) tudo entra direto na Central. **Recomendação:** A — rascunho é a regra do C211 e a triagem é editorial; filtro fino (tipo/período) é decisão de implementação com a assessoria. _(assumido — validar com produto)_ +- **Peça por link de perfil de terceiro (ex.: post que menciona o Solla):** **Opções:** A) entra só pelo link, sem extrair/baixar mídia | B) entra com thumbnail/embed quando o caminho oficial (oEmbed) permitir | C) não aceitar link de terceiro. **Recomendação:** B, com o arquivo nunca baixado — o caminho oficial de terceiro dá embed/thumbnail, não o arquivo; extração de mídia só para conteúdo próprio (conta do Solla via Graph API). _(assumido — validar com produto)_ +- **Periodicidade, se aprovada:** **Opções:** A) varredura diária agendada + "Sincronizar agora" | B) semanal | C) só sob demanda. **Recomendação:** A — a Central é acervo, não tempo real; a cadência de board (5 min) não serve, e o custo em chamadas da API é assunto da implementação. _(assumido — validar com produto)_ + +## Referências + +- Planos irmãos: `docs/plans/central-conteudos-ingestao.md` (C211) · `docs/plans/central-conteudos-publica.md` (S27) · `docs/plans/secao-conteudos-home-instagram.md` (S3) · `docs/plans/secao-conteudos-home-youtube.md` (S2) +- Runbook: `docs/ops/instagram-feed-token-runbook.md` · decisões do board: `docs/campanha/plano-site-campanha-2026.md` §4.2 +- Arquivos-pista: `src/globals/SocialFeedSettings.ts` · `src/utilities/socialFeed/instagramFeed.ts` · `src/utilities/socialFeed/instagramFeedView.ts` · `src/utilities/socialFeed/instagramSync.ts` · `src/utilities/socialFeed/youtubeFeed.ts` · `src/lib/speechVod.ts` +- Docs oficiais a abrir e datar na investigação: Instagram Platform / Graph API (`developers.facebook.com/docs/instagram-platform` — media, paginação, refresh de token) · Instagram oEmbed (`developers.facebook.com/docs/instagram/oembed`) · Termos da Plataforma Meta (`developers.facebook.com/terms`) · YouTube Data API v3 (`developers.google.com/youtube/v3/docs/videos` e `/search`) · YouTube oEmbed (`www.youtube.com/oembed`) · Termos/Developer Policies do YouTube (`developers.google.com/youtube/terms`) + +## Self-score (shaping) + +1. Fatia = um outcome verificável? **Sim** — as quatro perguntas respondidas com evidência + recomendação. +2. Appetite declarado e a intenção cabe? **Sim** (~0,5–1 dia; implementação, scraping e UI fora). +3. Persona + job + aceite claros sem jargão de stack? **Sim**. +4. Direção no codebase é hipótese? **Sim** — fatos verificados + áreas prováveis, sem contrato técnico. +5. Zero decisões duras de engenharia no plano? **Sim** — schema, agendador e limites ficam no item de implementação, se aprovado. + +**Score: 5/5.**