diff --git a/docs/plans/acervo-abrir-fonte-so-com-fonte-oficial.md b/docs/plans/acervo-abrir-fonte-so-com-fonte-oficial.md new file mode 100644 index 00000000..033d1a75 --- /dev/null +++ b/docs/plans/acervo-abrir-fonte-so-com-fonte-oficial.md @@ -0,0 +1,90 @@ +# Acervo: "Abrir fonte" só quando existe a fonte oficial (fim do atalho duplicado) + +Status: rascunho +Atualizado em: 2026-09-16 +Issue: #1087 +Priority: P3 +Impeccable: A — N/A sem nova superfície (remoção/ajuste de um botão) +Design UI: N/A — sem UI +Appetite: ~0,25–0,5 dia eng; um outcome verificável — nenhum botão do acervo leva a um vídeo sem marcar o ponto +Responsável: — + +## Intenção + +O acervo de falas mostra o botão "Abrir fonte" desde antes do C160. Depois que "Abrir no YouTube" chegou (com o timestamp da fala), o usuário relatou: *"O botão 'abrir fonte' se tornou inutil, já que agora temos o 'Abrir no Youtube', podemos remove-lo. Inclusive o link atual do 'Abrir fonte' vai para o video sem marcar o inicio, o que pode confundir o usuario."* + +O defeito concreto: quando a fala tem o PDF oficial do Diário (`officialTextUrl`), o botão está certo e aponta para a fonte oficial. Quando o import **não** resolveu o Diário, o código cai num fallback (`view.officialTextUrl ?? view.youtubeUrl`) e o botão abre o **vídeo cru no YouTube, sem timestamp** — exatamente o que "Abrir no YouTube" já faz melhor. Ou seja, hoje o mesmo botão às vezes é proveniência oficial e às vezes é um atalho pior e duplicado. Este item faz "Abrir fonte" significar uma coisa só: a fonte oficial. Sem fonte oficial, o botão não aparece. + +## Persona e fluxo + +- **Persona / contexto:** assessoria/comunicação e staff conferindo proveniência de uma fala no acervo; na mesa, com o detalhe ou a lista abertos, querem checar/citar a publicação oficial. +- **Job principal:** abrir a fonte oficial de uma fala quando ela existe, sem que um botão prometa "fonte" e entregue um vídeo sem o ponto. +- **Fluxo desejado:** abre a fala → se há Diário oficial, vê "Abrir Diário Oficial" e cai no PDF; se não há, o botão simplesmente não existe e "Abrir no YouTube" (no ponto da fala) é o caminho de vídeo. +- **Anti-goals de produto:** transformar "Abrir fonte" num segundo link de vídeo; esconder que a fonte oficial faltou com um link pior; mexer no "Abrir no YouTube" timestampado; redesenhar a tela; reimportar dados. + +## Objetivo e aceite + +- Nenhum botão rotulado como fonte aponta para uma URL de vídeo sem marcação de ponto. +- "Abrir fonte" (ou o rótulo substituto) só é renderizado quando `officialTextUrl` existe; sem ele, some — não cai no `youtubeUrl`. +- "Abrir no YouTube" permanece intocado, abrindo no ponto da fala. +- Acesso ao PDF oficial não é perdido silenciosamente onde ele existe (C160 preservado). +- Lista e detalhe se comportam igual: o mesmo critério de existência nos dois. +- **Guardrails:** sem schema/Consent/migration; sem tocar no VOD/MP4 nem no crédito "Fonte: Câmara dos Deputados · CC BY 4.0"; URL pública do acervo intocada; sem mudança de import. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — a superfície é um botão existente; nenhum número, série ou agregado é apresentado ou derivado. +- **Decisões desbloqueadas:** _N/A — sem métrica; a decisão do usuário (checar a fonte oficial) já existe e é servida ou não pelo botão._ +- **Forma:** _adiada ao plano de implementação_ — restrição de produto: o critério é "existe fonte oficial?", nunca "existe algum link?". + +## Dados da decisão (literais) + +- **Condição de exibição:** renderizar o botão **somente** quando `officialTextUrl` for não-nulo; remover o fallback `?? youtubeUrl` nos dois pontos: `src/app/(campaign)/campanha/(app)/comunicacao/acervo/[id]/page.tsx` e `src/utilities/speech/speechViewModels.ts`. +- **Rótulo proposto (pt-BR):** `Abrir Diário Oficial` (alternativas no gate: `Ver Diário Oficial`, `Abrir PDF oficial`) — deixa claro que é o registro oficial e não um vídeo. +- **Não mexer:** o botão/atalho "Abrir no YouTube" (`SpeechDetailPlayer.tsx`) e "Assistir na Câmara" seguem como estão, com timestamp. +- **Fallback proibido:** `youtubeUrl` nunca é destino do botão de fonte; `sourceUrl` deixa de representar "fonte ou vídeo". +- **Onde mais aparece:** card da lista `SpeechResultCard.tsx` — mesmo critério. +- **Comportamento do C160 preservado:** quando `officialTextUrl` existe, o destino continua sendo o PDF direto do Diário. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/components/campaign/speech/SpeechDetailPlayer.tsx` (render do botão, props), `src/components/campaign/speech/SpeechResultCard.tsx` (card da lista), `src/utilities/speech/speechViewModels.ts` (derivação de `sourceUrl`), `src/app/(campaign)/campanha/(app)/comunicacao/acervo/[id]/page.tsx` (passa a prop). +- **Precedente a olhar:** C160 `docs/plans/acervo-abrir-fonte-pdf-oficial.md` (dono do destino do link); `docs/plans/acervo-videos-comunicacao.md` (C154, atalho YouTube timestampado). +- **Risco de acoplamento:** `sourceUrl` pode ser lido por testes/e2e (`tests/e2e/campaignSpeechAcervo.e2e.spec.ts`) — a mudança de nome/semântica precisa acompanhar; não deixar a lista e o detalhe divergirem. + +## Dependências + +- Entregues (duras, satisfeitas): C160/#988 (PDF oficial como destino de "Abrir fonte"); C154 (acervo + "Abrir no YouTube" timestampado). +- Nenhuma dependência bloqueante. + +## Fora de escopo + +- Remoção total do botão (decisão de gate — ver Questões em aberto; ficaria como follow-up se escolhida). +- Backfill/resolução de Diários ausentes (é do C160; aqui não se cria fonte onde não há). +- Qualquer mudança no VOD/MP4, trechos, transcrições, import ou crédito CC BY. +- Redesenho da tela do acervo ou introdução de novo campo de fonte. + +## Rabbit holes de produto + +- **"Preencher o `officialTextUrl` que falta para todo mundo ter botão."** Se alguém "só completar": puxa a resolução offline do C160 de novo e um backfill — escopo de outro item. **Corte neste item:** sem fonte oficial, o botão não aparece. +- **"Manter o fallback mas com timestamp."** Se alguém "só completar": o botão de fonte vira clone do "Abrir no YouTube" — a duplicação que o usuário reclamou. **Corte neste item:** fonte é fonte; vídeo é vídeo. +- **"Aproveitar e remover o botão de vez."** Se alguém "só completar": some o acesso de um clique ao PDF oficial e o C160 perde sentido. **Corte neste item:** decisão consciente no gate, não efeito colateral. + +## Questões em aberto (produto) + +- **Remover o botão de vez (pedido literal) ou só endurecer a condição?** **Opções:** A) remoção total — perde o atalho ao PDF oficial onde ele existe; B) manter só quando há `officialTextUrl`, com rótulo explícito, sem fallback YouTube; C) manter os dois (fonte + YouTube) como hoje. **Recomendação:** B — resolve a confusão relatada (fim do vídeo sem ponto) sem jogar fora o acesso ao Diário oficial. _(decidido — produto 2026-09-16: manter apenas quando existe a fonte oficial; sem fallback de vídeo)_ +- **Qual rótulo?** **Opções:** A) `Abrir Diário Oficial` | B) `Ver Diário Oficial` | C) `Abrir PDF oficial`. **Recomendação:** A — nomeia o registro oficial e mantém o verbo do botão atual. _(assumido)_ +- **Lista e detalhe com o mesmo texto?** **Opções:** A) sim, mesmo rótulo | B) lista mais curto. **Recomendação:** A — uma regra só, menos surpresa. _(assumido)_ + +## Referências + +- GitHub Issue #1087 +- Design UI (gate): N/A — sem UI +- `src/components/campaign/speech/SpeechDetailPlayer.tsx` (botão "Abrir fonte"; "Abrir no YouTube") +- `src/components/campaign/speech/SpeechResultCard.tsx` · `src/utilities/speech/speechViewModels.ts` · `src/app/(campaign)/campanha/(app)/comunicacao/acervo/[id]/page.tsx` +- `docs/plans/acervo-abrir-fonte-pdf-oficial.md` (C160/#988) · `docs/plans/acervo-videos-comunicacao.md` (C154) +- `AGENTS.md` — convenções de i18n (rótulo pt-BR) e rotas `/campanha` + +## Self-score (shaping) + +5/5 — (1) fatia = um outcome verificável (nenhum botão de fonte leva a vídeo sem ponto); (2) appetite ~0,25–0,5 dia, dois sítios de render; (3) persona + job + aceite claros; (4) direção no codebase é hipótese; (5) zero decisão dura de engenharia. diff --git a/docs/plans/acervo-encontrar-cortes-ui-design.html b/docs/plans/acervo-encontrar-cortes-ui-design.html new file mode 100644 index 00000000..6ee25a4d --- /dev/null +++ b/docs/plans/acervo-encontrar-cortes-ui-design.html @@ -0,0 +1,251 @@ + + + + + + + Design — C174 · Acervo: encontrar cortes + + + +
+
+
+ C174 · gate hi-fi + Campanha · Comunicação +
+

Encontrar cortes sem recortar de novo

+

A assessoria reencontra um corte pela navegação, pela fala de origem ou pela busca. Cenas estáticas para aprovar hierarquia, estados, densidade e responsividade.

+
+ + +
+
+
+

CENA 01

+

Nav subitems · desktop · 256 px

+
+ +
+
+ + + +
+
+ + +
+
+

CENA 02

+

Fala · desktop ~1280 · Cortes desta fala (populado)

+
+
+
+ +
+

Pequeno Expediente

Data da fala · Câmara dos Deputados

+
+ ← Voltar ao acervo +
+
+

Pequeno Expediente

+

Data da fala · Fase da sessão · 12:34

+
+
▶
NEEDS ASSET — miniatura real do vídeo
+
+
+ +
+ +
+

Cortes desta fala

Abra um corte existente para editar ou reaproveitar.

+
+
TítuloStatusDuraçãoAção
+

Trecho selecionado da fala

Publicado00:48Abrir corte
+

Declaração para redes

Despublicado01:06Abrir corte
+

Trecho em preparação

Processando00:36Abrir corte
+

Trecho com falha

Falhou00:29Abrir corte
+
+
+
+
+
+
+
+ + +
+
+

CENA 03

+

Fala · desktop ~1280 · Cortes desta fala (vazio)

+
+
+
+ +

Grande Expediente

Data da fala · Câmara dos Deputados

← Voltar ao acervo

Grande Expediente

Data da fala · 10:42

NEEDS ASSET — miniatura real do vídeo
+

Cortes desta fala

Nenhum corte desta fala ainda

Selecione um trecho no player para criar o primeiro corte.

Selecionar trecho
+
+
+
+
+ + +
+

CENA 04

Busca no acervo · fala encontrada com corte aninhado

+
+

Acervo de falas

Encontre falas por tema, local ou palavra-chave

AnoTemaMunicípio
+
Data da fala·Pequeno Expediente·12:34

… trecho da fala em que o tema pesquisado aparece no contexto …

Tema da falapalavra-chave
▶ Ver fala +

1 corte desta fala

Publicado00:48

Trecho sobre o tema pesquisado

Abrir corte →
+

1 fala encontrada

+
+
+ + +
+

CENA 05

Busca no acervo · corte casa, fala aparece como origem (opção B)

+

Acervo de falas

Resultado mantido em uma única lista

Biblioteca de cortes
⌕
+
Fala de origem·Data da fala·Grande Expediente

A fala não contém o termo exato; ela aparece porque um corte vinculado corresponde à busca.

Ver fala

Correspondência no corte

Despublicado01:06

Título com a expressão do corte

Descrição curta do corte correspondente.

Abrir corte →

1 fala encontrada por corte vinculado

+
+ + +
+

CENA 06

Mobile ~390 · resultado aninhado + seção da fala

+
+
S

Acervo de falas

Comunicação

⌕
AnoTemaMunicípio
+

Data da fala · Pequeno Expediente · 12:34

… trecho da fala sobre o tema pesquisado …

Tema da fala
Ver fala

1 corte desta fala

Publicado00:48

Trecho sobre o tema pesquisado

Abrir corte

1 fala encontrada

⌂Início
⌖Municípios
◉Atualizações
□Agenda
•••Mais
+ +
←

Pequeno Expediente

Data da fala

Pequeno Expediente

Data da fala · 12:34

NEEDS ASSET — miniatura real

Cortes desta fala

Publicado00:48

Trecho selecionado da fala

Abrir corte
Processando00:36

Trecho em preparação

Abrir corte
+
+
+ + +
+

CENA 07

Biblioteca de cortes · glimpse do destino

+

Biblioteca de cortes

Cortes guardados para editar, baixar e republicar

⌕

2 cortes encontrados

+
+ + +
+ + diff --git a/docs/plans/acervo-encontrar-cortes.md b/docs/plans/acervo-encontrar-cortes.md new file mode 100644 index 00000000..1b728b1f --- /dev/null +++ b/docs/plans/acervo-encontrar-cortes.md @@ -0,0 +1,109 @@ +# Acervo: encontrar cortes — na navegação, na fala e na busca + +Status: rascunho +Atualizado em: 2026-09-16 +Issue: #1084 +Priority: P2 +Impeccable: C — fluxo/chrome novo na vertical Comunicação (nav + seção na fala + resultados de busca) +Design UI: docs/plans/acervo-encontrar-cortes-ui-design.html +Appetite: ~1,5–2 dias eng; um outcome verificável — a assessoria reencontra um corte existente (pela navegação, pela fala de origem ou pela busca) e o reaproveita, sem duplicar. +Responsável: — + +## Intenção + +Quatro pedidos da assessoria são o mesmo job: **achar e reaproveitar um corte que já existe**. Uma tentativa anterior (C168/#1015) chegou a merged no repo, mas o dono testou o ambiente e **não encontrou a edição** — o que está de pé precisa ser conferido e o fluxo, tornado achável. Hoje, na prática, só se chega à biblioteca por um botão dentro do Acervo de falas, e nada na página da fala lembra que já se cortou dali, então a pessoa refaz o corte. Na busca do acervo, cortes simplesmente não existem. Esta entrega coloca os cortes no caminho: um subitem na navegação de "Comunicação", uma seção "Cortes desta fala" no detalhe da fala e os cortes aparecendo na busca do acervo. É descoberta e reuso; nada de novo modelo de dados. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`, mais `coordinator`/`candidate`) na mesa, correndo para publicar; muitas vezes dias depois do corte ter sido feito por outra pessoa. +- **Job principal:** em uma tela, saber se aquela fala ou tema já rendeu corte e abrir para reusar/editar — sem recortar de novo. +- **Fluxo desejado:** abre "Comunicação" na barra, vê "Acervo de falas" e "Biblioteca de cortes"; busca um tema, vê a fala e, aninhado, os cortes já feitos dela; abre a fala e ali há a lista dos cortes com status e link; abre qualquer corte e edita/reusa. +- **Anti-goals de produto:** não criar um segundo cadastro de corte nem uma segunda lista concorrente com a busca; não virar editor de fala; não expor internals de corte em superfície pública. + +### Esboço de fluxo (C) + +```text +[Comunicação] ──┬─→ [Acervo de falas] ─→ [busca "reforma tributária"] + │ └─ [fala + cortes aninhados] ─→ [corte: editar/reusar] + └─→ [Biblioteca de cortes] ─→ [lista completa] ─→ [detalhe: editar/reusar/share] + +[fala (detalhe)] ─→ seção "Cortes desta fala" ─┬─→ [corte existe] ─→ [abrir na biblioteca] + └─→ [vazio] ─→ [Selecionar trecho] (C166/C167) +``` + +### Design UI (C) + +- Design UI (gate): `docs/plans/acervo-encontrar-cortes-ui-design.html` + +## Objetivo e aceite + +- "Comunicação" ganha subitens visíveis: **Acervo de falas** e **Biblioteca de cortes** — a biblioteca e a edição ficam a um clique de qualquer lugar da vertical. +- O detalhe da fala mostra os cortes já feitos **daquela** fala (título, status, duração, link para o detalhe do corte), com vazio honesto quando não há. +- A busca do acervo mostra os cortes como **subitens da fala de origem** no resultado; cortes não viram uma lista paralela e confusa. +- **Guardrails:** gate é `speechCatalog` (communicator/coordinator/candidate); `advisor`/`leader` negados fail-closed, sem regressão em nada do C168. +- Corte sempre pertence a uma fala; a fala pode ter sido excluída (FK `SET NULL`) e a UI degrada sem quebrar. +- Nenhum internals de corte (media/status cru/erro) vaza; `/corte/` público intocado. +- Sem collection nova, sem `Consent`, sem migration. + +## Dados (intenção) + +- **Vou apresentar dados?** Sim, superfície neste item: **uma lista paginada** (a biblioteca de cortes, já do C168) e **um resultado de busca** (cortes aninhados no acervo de falas). **Sem KPI agregado** — não há decisão que peça contagem/gráfico de cortes. +- **Decisões desbloqueadas:** assessoria escolhe *reusar/editar* vs *cortar de novo* ao ver o corte existente na fala; escolhe *abrir a biblioteca* vs seguir navegando ao vê-la no chrome. +- **Forma:** *adiada ao plano de implementação* — aqui só restrição de produto: contagem honesta na lista ("N cortes"), sem percentual/taxa. + +## Dados da decisão (literais) + +- Rotas: acervo `/campanha/comunicacao/acervo`; biblioteca `/campanha/comunicacao/acervo/cortes`; detalhe do corte `/campanha/comunicacao/acervo/cortes/[id]`; detalhe da fala `/campanha/comunicacao/acervo/[id]`; pública `/corte/` **intocada**. +- Rótulos de nav (pt-BR): pai **"Comunicação"**; subitens **"Acervo de falas"** e **"Biblioteca de cortes"**. +- Regra de aninhamento na busca: o corte aparece **como subitem indentado abaixo do item da fala de origem**, só quando a fala está no resultado e tem ≥1 corte; **não** existe grupo "Cortes" separado no v1. +- Cabeçalho da seção na fala: **"Cortes desta fala"**. +- Vazio na fala sem cortes: título **"Nenhum corte desta fala ainda"**, descrição **"Selecione um trecho no player para criar o primeiro corte."**, CTA **"Selecionar trecho"**. +- Texto da busca do acervo passa a valer também sobre cortes da fala; rótulo segue "Buscar fala por termo". +- Estado de cada corte na fala: badges `Publicado`/`Despublicado`/`Processando`/`Falhou` (mesmos do C168). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** nav em `src/components/campaign/shell/nav.ts` (`CampaignNavItem` hoje é plano — precisa de subitens/ativo); caminhos em `src/lib/campaignPaths.ts`; página da fala `src/app/(campaign)/campanha/(app)/comunicacao/acervo/[id]/page.tsx`; loader novo de cortes-por-fala em `src/utilities/speech/speechPageData.ts` (hoje só lista-tudo/detalhe em `speechCutPageData.ts` e `findSpeechCutForActor` em `speechCutData.ts`); resultado `SpeechResultList`/`speechViewModels.ts`; `src/components/campaign/speech/`. +- **Precedente a olhar:** C154 (nav própria do communicator + gate `speechCatalog`), C168 (biblioteca/detalhe/editora de título), C166/C167 (selecionar trecho/cortar), C170 (teto removido). +- **Risco de acoplamento:** não duplicar a lista de cortes — reusar `loadSpeechCutAcervoPageData`/view models do C168; a busca continua em `speech.searchText` (não criar `searchText` de corte agora); respeitar o lockdown `advisor`/`leader`. + +## Dependências + +- **C168/#1015** — tentativa anterior (biblioteca, detalhe, edição, kill switch) merged em `main`, mas o dono relata que **não encontra a edição**; validar a superfície no ambiente real antes de assumir que existe e, então, torná-la achável. +- **C154** (entregue) — gate `speechCatalog` e nav do communicator. +- **C166/C167/C170** (entregues) — de onde o corte nasce no detalhe da fala; o CTA de vazio aponta para o fluxo deles (suave). + +## Fora de escopo + +- Editar título/descrição em si — já é do C168; aqui só se chega à tela. +- Qualquer mudança no contrato público `/corte/` (unlisted, `noindex`, sem transcript). +- Facetas/filtros de corte (ano, fala de origem, status) na biblioteca — C168 é só `q` + paginação. +- Corte em massa / edição em lote / deduplicação automática. +- Busca acento-insensível e índice para corte (gatilho do C168: ~5–10 mil cortes) — vira item próprio se o volume pedir. +- Corte criado de dentro da busca (cortar direto de um resultado). + +## Rabbit holes de produto + +- **Redesenhar toda a IA do shell.** Se alguém "só completar" a navegação, refaz a sidebar inteira. **Corte neste item:** só a árvore de "Comunicação" ganha subitens; o resto do `nav.ts` fica igual. +- **Editar o corte dentro da fala.** A tentação é editar título/descrição ali mesmo e criar um segundo editor. **Corte neste item:** a fala só **lista e linka**; a edição continua morando no detalhe (C168). +- **Unificar a busca dos dois acervos.** Virar uma query única com `searchText` de corte exige migration/índice. **Corte neste item:** busca continua por fala; corte só aninhado. +- **Segunda lista de cortes.** "Cortes encontrados" como grupo separado recria a duplicação que motivou o pedido. **Corte neste item:** só aninhamento sob a fala. + +## Questões em aberto (produto) + +- **Corte que casa por título/descrição mas cuja fala não casa?** **Opções:** A (não aparece no v1) | B (traz a fala de origem como bloco-resultado, com o corte aninhado) | C (grupo "Cortes" separado). **Recomendação:** B — mantém uma lista única e ainda responde ao pedido "na busca também apareça cortes". _(assumido — validar com produto)_ +- **Nav: subitens expansíveis vs abas na home da Comunicação?** **Opções:** A (subitens no item "Comunicação") | B (tabs). **Recomendação:** A — pedido literal ("subitems dentro de Comunicação") e reaproveita o padrão de nav existente. +- **Manter o botão "Biblioteca de cortes" no topo do acervo?** **Opções:** A (manter como atalho redundante) | B (remover). **Recomendação:** A — custo zero e ajuda quem já tem o reflexo; o subitem é o caminho novo. +- **Status do corte aparece na busca?** **Opções:** A (só título + duração) | B (título + status). **Recomendação:** B — "reaproveitar" pressupõe saber se está publicado; sem custo relevante. + +## Referências + +- GitHub Issue #1084 +- Design UI (gate): `docs/plans/acervo-encontrar-cortes-ui-design.html` (+ `docs/plans/acervo-encontrar-cortes-ui-design-assets/` se houver SVG próprio) +- `docs/changelog/2026-09-15-c168.md` (biblioteca/edição), `docs/changelog/2026-09-13-c154.md` (nav/gate do communicator) +- Rotas/utilitários: `src/components/campaign/shell/nav.ts`, `src/lib/campaignPaths.ts`, `src/utilities/speech/speechCutPageData.ts`, `src/utilities/speech/speechPageData.ts`, `src/utilities/speech/speechCutListUrl.ts` +- `AGENTS.md` — lockdown de papéis de campanha e "edite o dono, não gema um irmão" + +## Self-score (shaping) + +5/5 — (1) fatia = um outcome verificável ("reencontrar e reusar um corte" pelos três caminhos); (2) appetite ~1,5–2 dias, sem schema/migration; (3) persona + job + aceite testáveis; (4) direção no codebase é hipótese (aponta donos sem travar solução); (5) zero decisão dura de engenharia. diff --git a/docs/plans/acervo-player-preview-do-trecho-ui-design.html b/docs/plans/acervo-player-preview-do-trecho-ui-design.html new file mode 100644 index 00000000..e9b382c8 --- /dev/null +++ b/docs/plans/acervo-player-preview-do-trecho-ui-design.html @@ -0,0 +1,344 @@ + + + + + + + Design — Acervo: pré-visualizar trecho + + + +
+
+

C173 · Design de gate

+

Pré-visualizar o trecho selecionado

+

+ Assessoria de comunicação confere o intervalo no mesmo player antes de compartilhar ou cortar. + O controle pertence à seleção; a fileira de ações permanece intacta. +

+
+ + +
+
Cena 01 · Desktop · viewport de referência 1280 px
+
+
+ + +
+
+
+ Comunicação + + Detalhe da fala +
+
AS
+
+ +
+ + + Voltar ao acervo + +
+
+

Fala em sessão plenária

+

Transcrição e vídeo da fala · data da sessão

+
+ Discurso +
+ +
+
+
+
Vídeo da Câmara
+
+
+
+ +
+

NEEDS ASSET — thumbnail da fala

+
+
+
+
+
02:1405:42
+
+
+ + +
+
+ Trecho selecionado + 01:42 → 02:14 · 32 s +
+
+
+
+
+
+
+
00:0001:4202:1405:42
+
+

Clique nas frases: o limite encaixa no segmento (ímã). Arraste as alças para o ajuste fino. Mínimo 5s · sem limite — até o fim da fala.

+ +
+
+ +
+ + + + + +
+
+ + +
+ +
+

Estados do controle no mesmo bloco de seleção

+

A ação não migra para a fileira de compartilhar, cortar ou baixar.

+
+
+
Trecho selecionadoPARADO
+

01:42 → 02:14 · 32 s

+ +
+
+
Trecho selecionadoREPRODUZINDO
+

01:42 → 02:14 · 32 s

+ +
+
+
Trecho selecionadoFIM VISÍVEL · 02:14
+

01:42 → 02:14 · 32 s

+ +
+
+
+
+
+
+
+
+ + +
+
Cena 02 · Mobile · viewport de referência 390 px
+
+
+ + Campanha + AS +
+
+ Voltar ao acervo +

Fala em sessão plenária

+

Transcrição e vídeo da fala

+ +
+
+
+
+

NEEDS ASSET — thumbnail da fala

+
+
+
+
+ +
+
+ Trecho selecionado + 01:42 → 02:14 · 32 s +
+
+
+
+
+
+
+
00:0001:4202:1405:42
+

Arraste as alças para o ajuste fino. Mínimo 5s · sem limite — até o fim da fala.

+ +
+ +
+ + + + + +
+
+
+
+ + +
+
Cena 03 · YouTube · limitação explícita e saída honesta
+
+
+
+
+
YouTube
+

NEEDS ASSET — thumbnail da fala

+
+
+
+ +

No YouTube, a pré-visualização começa no início do trecho — parar no fim exige o vídeo da Câmara.

+
+
+ + +
+
+
+
+ Trecho selecionado +

01:42 → 02:14 · 32 s

+
+ +

Começa em 01:42. No YouTube, a parada no fim é manual.

+
+
+
+
+ + +
+
Cena 04 · Sem superfície tocável · seleção preservada
+
+
+
+ +

Vídeo indisponível neste momento.

+

Esta fala não tem vídeo da Câmara nem ponto de início disponível no YouTube. A seleção continua disponível para compartilhar ou cortar.

+
+
+
+
Trecho selecionado32 s
+

01:42 → 02:14

+
+

A seleção permanece ajustável. Pré-visualização não oferecida nesta superfície.

+
+
+ + +
+
+
+
+
+ +
+ Design de gate · The Field Desk · Inter, stone-white, hairlines e Mandate Red apenas para ação primária, seleção e foco. +
+
+ + diff --git a/docs/plans/acervo-player-preview-do-trecho.md b/docs/plans/acervo-player-preview-do-trecho.md new file mode 100644 index 00000000..4713da14 --- /dev/null +++ b/docs/plans/acervo-player-preview-do-trecho.md @@ -0,0 +1,104 @@ +# Acervo: pré-visualizar no player o trecho selecionado + +Status: rascunho +Atualizado em: 2026-09-16 +Issue: #1083 +Priority: P2 +Impeccable: B — encaixe no player do detalhe do acervo (controle de seleção) +Design UI: docs/plans/acervo-player-preview-do-trecho-ui-design.html +Appetite: ~1 dia eng; um outcome verificável — antes de cortar, a assessoria aperta play e vê exatamente o que entra no corte. +Responsável: — + +## Intenção + +A assessoria já marca [início, fim] no acervo (C166/C170), compartilha o link (C166) e corta o arquivo (C167). Mas entre marcar e cortar falta o gesto mais óbvio: **ver o trecho**. Hoje o play do player toca a fala inteira; para conferir se o intervalo escolhido começa e termina onde ela quer, ela precisa caçar os segundos no dedo. O pedido é direto: com um trecho selecionado, apertar play e ver só o intervalo — tocar de início e parar no fim — para decidir com os olhos antes de criar o corte. Não é editar nem pré-renderizar: é o mesmo player, com a janela selecionada. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (communicator, coordenação e candidatura) em `/campanha/comunicacao`, montando peça com prazo curto, na mesa ou no celular. +- **Job principal:** conferir no player que o trecho selecionado é exatamente o que entra no corte, antes de compartilhar ou cortar. +- **Fluxo desejado:** abre a fala → "Selecionar trecho" → ajusta [início, fim] (frases/alças) → aperta **"Pré-visualizar trecho"** → o player toca do início e para no fim → ajusta se algo entrou/saiu do ponto → segue para "Compartilhar" (C166) ou "Cortar vídeo" (C167) com confiança de que o intervalo é o certo. +- **Anti-goals de produto:** não é editor de vídeo (trim/export/render), não é segundo player, não promete controle que o embed do YouTube não dá; seleção/compartilhamento/corte intactos; sem `Consent`/collection/migration. + +### Esboço de fluxo (B) + +```text +[seleção ativa: início→fim] → "Pré-visualizar trecho" → player toca [início, fim] e para no fim +→ "certo, era isso" → [Compartilhar (C166) | Cortar vídeo (C167)] +→ "quase" → ajusta alças/frases → pré-visualiza de novo +[superfície sem controle do fim (YouTube)] → honesto: reposiciona no início; sem prometer parada automática +``` + +### Design UI (B) + +- Design UI (gate): `docs/plans/acervo-player-preview-do-trecho-ui-design.html` — cenas: barra de seleção com o controle "Pré-visualizar trecho" (parado / tocando), estado chegou-ao-fim, aviso honesto no player do YouTube, fala sem superfície tocável, mobile (~390px) e desktop (~1280px). + +## Objetivo e aceite + +- Com trecho selecionado em superfície que o app controla (vídeo da Câmara), "Pré-visualizar trecho" toca somente [início, fim]: posiciona no início, reproduz e **para no fim**. +- Se a seleção mudar durante/após a pré-visualização, o player reflete o novo intervalo (não continua tocando o antigo); a pré-visualização nunca vaza para fora do trecho selecionado. +- No embed do YouTube, a postura é honesta: o app não promete parada automática no fim; a pré-visualização reposiciona no início do trecho (ou a UI oferece o vídeo da Câmara quando houver trecho gerado), com aviso claro e sem inventar controle que o embed não dá. +- Seleção/compartilhamento/corte intactos; clique na transcrição continua posicionando fora do modo de seleção e estendendo o trecho dentro dele (C166). +- **Guardrails:** gate do acervo (communicator/coordinator/candidate; advisor/leader negados fail-closed); crédito "Fonte: Câmara dos Deputados · CC BY 4.0"; `excerptTMs`/seleção exata verbatim; sem segundo player; sem render/export; sem `Consent`/collection/migration; URLs públicas intocadas. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — a superfície é o player e o controle de seleção; tocar/parar é feedback de ação, não dado do acervo. +- **Decisões desbloqueadas:** a assessoria decide ajustar (ou não) o intervalo **antes** de criar o corte; a coordenação herda cortes já conferidos (menos retrabalho na biblioteca do C168). +- **Forma:** _adiada ao plano de implementação_ — restrição: sem KPI/telemetria de pré-visualização nesta fatia. + +## Dados da decisão (literais) + +- Controle (pt-BR), na barra/bloco de seleção: rótulo **"Pré-visualizar trecho"** (ícone play); enquanto toca, vira **"Parar pré-visualização"**. +- Comportamento no vídeo da Câmara: `currentTime = início` → play → ao alcançar `fim`, pausa e deixa o fim visível (play pronto). +- Aviso honesto do YouTube (pt-BR): **"No YouTube, a pré-visualização começa no início do trecho — parar no fim exige o vídeo da Câmara."** Quando a fala tem trecho gerado, oferecer o caminho da Câmara (reuso do C171) em vez de só avisar. +- Sem superfície tocável (sem VOD e sem offset do YouTube): a pré-visualização não é oferecida; a seleção permanece para compartilhar/cortar. +- Não alterar rótulos/limites vigentes da seleção: mínimo 5 s, sem teto (até o fim da fala), fileira de ações atual. +- Sem novas chaves de `Consent`, collections ou migrations; nada persistido no servidor. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/components/campaign/speech/SpeechDetailPlayer.tsx` (dono do playback: `videoRef`, `seekTo`, estados de seleção) e o bloco de seleção em `src/components/campaign/speech/SpeechExcerptControls.tsx`. +- **Precedente a olhar:** C166/C170 (`SpeechExcerptControls` só traduz ponteiro/tecla em geometria pura — não é lugar de lógica de player), C171 (troca de superfície e saídas do YouTube), seek já existente (`seekTo`) e o `onTimeUpdate` do `