From 4bf0c0c0c61069cd7edaf63dcb4de200375f0f4d Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Sat, 26 Sep 2026 02:00:32 -0300 Subject: [PATCH] =?UTF-8?q?docs(C231=E2=80=93C234):=20planos=20+=20designs?= =?UTF-8?q?=20hi-fi=20do=20acervo=20de=20fotos=20do=20Flickr=20(Related=20?= =?UTF-8?q?#1366,=20#1367,=20#1368,=20#1369)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plans/acervo-fotos-catalogacao-ia.md | 109 +++ docs/plans/acervo-fotos-flickr-ingestao.md | 91 +++ .../album-fotos-publico-busca-ui-design.html | 668 +++++++++++++++++ docs/plans/album-fotos-publico-busca.md | 111 +++ .../busca-fotos-por-selfie-ui-design.html | 680 ++++++++++++++++++ docs/plans/busca-fotos-por-selfie.md | 106 +++ 6 files changed, 1765 insertions(+) create mode 100644 docs/plans/acervo-fotos-catalogacao-ia.md create mode 100644 docs/plans/acervo-fotos-flickr-ingestao.md create mode 100644 docs/plans/album-fotos-publico-busca-ui-design.html create mode 100644 docs/plans/album-fotos-publico-busca.md create mode 100644 docs/plans/busca-fotos-por-selfie-ui-design.html create mode 100644 docs/plans/busca-fotos-por-selfie.md diff --git a/docs/plans/acervo-fotos-catalogacao-ia.md b/docs/plans/acervo-fotos-catalogacao-ia.md new file mode 100644 index 00000000..9f83a7e3 --- /dev/null +++ b/docs/plans/acervo-fotos-catalogacao-ia.md @@ -0,0 +1,109 @@ +# C232 — Catalogação com IA do acervo de fotos + +Status: rascunho +Atualizado em: 2026-09-26 +Issue: #1367 +Priority: P2 +Impeccable: B — encaixe de curadoria na ficha/lista existentes do admin/Central, sem rota pública nova; se o gate pedir superfície de revisão própria, o design nasce no gate (HTML abaixo) +Design UI: N/A — superfície admin (ficha/lista existentes); design próprio só se o gate pedir: `docs/plans/acervo-fotos-catalogacao-ia-ui-design.html` +Appetite: ~2 dias eng + tempo de processamento em lote (6,5k fotos) +Responsável: — + +## Intenção + +O acervo de fotos entrou para dentro de casa (C231) e virou uma pilha de 6,5k imagens sem ficha: achar a foto da plenária em Vitória da Conquista ou do Solla com uma liderança em Feira é garimpo manual. Cada foto precisa virar encontrável — legenda, atividade, local, pessoas públicas presentes, texto de faixas/placas (OCR) e descrição semântica. A IA pré-cataloga em lote; a curadoria humana revisa e vence a IA; nome de pessoa nunca é inventado de rosto. Sem isso, o álbum público (C233) não tem por onde buscar. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação (`communicator`; `coordinator`/`candidate` também) na mesa, diante de um lote de milhares de fotos e do pouco tempo de revisão. +- **Job principal:** transformar o acervo bruto em acervo encontrável — conferir e corrigir a pré-catalogação da IA, sem revisar tudo do zero. +- **Fluxo desejado:** o lote é catalogado → cada foto ganha ficha pré-catalogada (legenda, atividade/cena, local, pessoas, texto visível, temas, descrição semântica) → a assessoria abre a lista/ficha, revisa e corrige o que importa → a correção permanece (a IA não sobrescreve) → encontra a foto por local/data/atividade/pessoa/termo → recibo honesto do lote ao fim. +- **Anti-goals de produto:** não é o álbum público (C233) nem a busca facial (C234); não inventa nome de pessoa; não expõe nada ao público; não cria segundo cadastro de pessoa; não vira CMS de fotos com edição de imagem. + +### Esboço de fluxo (B) + +```text +[acervo C231] → passe de catalogação em lote (IA) + → por foto: legenda/descrição · atividade/cena · local (gazetteer) · pessoas públicas (catálogo curado) · texto visível (OCR) · temas · descrição semântica + → ficha pré-catalogada revisável na lista/ficha existentes + → assessoria revisa e corrige → correção vence a IA + → busca interna por local/data/atividade/pessoa/termo + → recibo do lote: processadas · puladas · falharam com motivo (reexecutável, sem duplicar) +[outcome: 6,5k fotos encontráveis — sem nome inventado e sem nada publicado] +``` + +### Design UI (B) + +- Design UI: N/A — a curadoria acontece na ficha/lista existentes (superfície admin); não há tela nova a desenhar. Se o gate concluir que a revisão do lote precisa de fila/galeria própria, o design nasce no gate em `docs/plans/acervo-fotos-catalogacao-ia-ui-design.html`. + +## Objetivo e aceite + +- Toda foto do acervo ganha ficha pré-catalogada revisável (ou estado honesto de "nada a propor"), com: legenda/descrição pt-BR, atividade/cena, local, pessoas públicas, texto visível, temas e descrição semântica. +- A busca interna por local, data, atividade, pessoa pública e termo funciona sobre o catálogo — e nada disso é exposto ao público. +- Curadoria vence a IA: reexecutar o passe nunca sobrescreve campo já editado por humano. +- O passe é em lote, não interativo: falha de uma foto não derruba o lote; ao fim há recibo honesto "processadas / puladas / falharam com motivo"; reexecutar não duplica nem reprocessa o que já está catalogado. +- Nenhum nome de pessoa é inferido de rosto; pessoas só do catálogo curado e com confirmação humana. Rosto, quando marcado, é presença (tag de cena) — sem identificação biométrica. +- **Guardrails:** acervo interno (gate de leitura coerente com a Central); PII/rostos de cidadãos não vão a terceiro sem decisão explícita e contrato; provider reservado aos agentes de design não entra no app. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — catalogação não é métrica; o recibo do lote (processadas/puladas/falharam) é operacional, não agregado de leitura. +- **Decisões desbloqueadas:** N/A — a decisão da assessoria é editorial (revisar/corrigir/usar a foto), não numérica. +- **Forma:** adiada ao plano de implementação — restrição de produto: nenhum score/confiança numérico exposto na ficha; o recibo do lote é só contagem honesta. + +## Dados da decisão (literais) + +- Por foto, a IA deve propor: **legenda/descrição pt-BR**, **atividade/cena**, **local** (município pelo gazetteer existente; Salvador/zona ambíguo → null), **pessoas públicas** (só do catálogo curado `publicFigureCatalog` — nunca inferir nome de rosto sem confirmação humana), **texto visível** (OCR de faixas/placas/banners), **tags/temas** do vocabulário existente e **descrição semântica/embedding** para busca futura. +- **Curadoria vence a IA:** campo já curado por humano nunca é sobrescrito (precedente `curatedFields`). +- **Processamento em lote, não interativo**: falha por foto não derruba o lote; recibo honesto "processadas / puladas / falharam com motivo"; reexecução idempotente por foto. +- **Face/rosto**: nesta fatia, no máximo detectar **presença de pessoa/rosto** como tag de cena — **sem identificação biométrica** (isso é C234). Nome de pessoa só por catálogo curado e revisão humana. +- **Engine de visão a decidir na implementação** (não fixar fornecedor aqui): opções local/self-hosted vs API de terceiro; restrição de produto: PII/rostos de cidadãos não vão para terceiro sem decisão explícita e contrato; provider reservado aos agentes de design não entra no app. +- Curadoria/edição por assessoria no admin, com gate de leitura coerente com a Central de Conteúdos. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** catalogação `src/utilities/content/` (C230 já usa esse pipeline — reusar, não duplicar engine); job/agendador sem cron como `contentPieceJob.ts`/`contentPieceScheduler.ts`; `src/utilities/ai/` (chamadas com timeout e fallback); `src/lib/speechFacets.ts` (temas), `src/lib/publicFigureCatalog.ts` (pessoas), `src/lib/speechGazetteer.ts` (municípios); access `src/utilities/access/contentPieces.ts` + barrel; grupo admin `'Comunicação'`; migration via `pnpm migrate:create` (`push:false`). +- **Precedente a olhar:** C211/C220/C230 (pipeline, ficha e curadoria que vence IA), C226 (passo que não derruba o job), C153 (classificador + gazetteer), C231 (dono do acervo — shape fica lá). +- **Risco de acoplamento:** não criar segundo engine de catalogação; `curatedFields` é o mecanismo de precedência; `src/utilities/ai` e `src/lib/schemas` são prefixes de risco fail-closed no CI (pins `contentPieceCataloging.unit.spec.ts`, `expandSpeechSearchTheme.unit.spec.ts`); `openai/*` fica fora do app (OPS123). + +## Dependências + +- **Dura:** C231 — sem o acervo dentro de casa não há lote nem ficha. +- **Soft:** C211/C220/C230 (pipeline e precedentes de curadoria), C153 (classificador), C226 (job isolado), C229 (embedding restrito ao acervo de falas como precedente). + +## Fora de escopo + +- Álbum público (C233) e busca facial/identificação biométrica (C234). +- Vídeos, saneamento/tratamento de imagem, analytics de acervo. +- Publicação de qualquer foto; edição/recorte de imagem; segundo cadastro de pessoa. + +## Rabbit holes de produto + +- **"Só completar" rotulando cada rosto manualmente.** Se alguém "só completar": revisão identidade a identidade de 6,5k fotos = semana de trabalho. **Corte neste item:** a IA pré-cataloga; o humano revisa por exceção; rosto é tag de cena (identidade é C234). +- **Reescrever a taxonomia de temas.** Se alguém "só completar": nova ontologia para o acervo. **Corte neste item:** vocabulário existente (`speechFacets`). +- **API de visão de terceiro sem decisão de PII.** Se alguém "só completar": manda foto de cidadão para fora "para testar". **Corte neste item:** engine decidido na implementação sob a restrição de produto; sem decisão explícita e contrato, nada de PII para terceiro. +- **Catalogar tudo com humano em vez de IA.** Se alguém "só completar": descrição manual foto a foto. **Corte neste item:** lote com IA + curadoria por exceção. + +## Questões em aberto (produto) + +- **Engine de visão?** **Opções:** A) local/self-hosted | B) API de terceiro | C) híbrido (local para tudo sensível). **Recomendação:** A — o lote não é interativo e roda em casa; PII/rostos não saem sem contrato; se a qualidade não fechar o aceite, reabre com B/C e decisão explícita de PII. _(assumido — validar com produto)_ +- **Quanto de curadoria humana por foto no v1?** **Opções:** A) amostragem | B) 100% revisado | C) por exceção (baixa confiança + o que for usado). **Recomendação:** C — 100% de 6,5k é semana de trabalho e amostragem não protege o que importa; campo de pessoa sempre passa por confirmação humana. _(assumido — validar com produto)_ +- **Foto sem metadado de local (geotag raro)?** **Opções:** A) gazetteer só pelo texto de álbum/título/OCR | B) não tentar (null) | C) pedir local à assessoria. **Recomendação:** A — tentar pelo texto disponível; sem sinal, null honesto; nunca chutar. _(assumido — validar com produto)_ + +## Referências + +- GitHub Issue [#1367](https://github.com/fsolla/teqo/issues/1367) +- Design UI: N/A — superfície admin; design próprio só se o gate pedir: `docs/plans/acervo-fotos-catalogacao-ia-ui-design.html`. +- Planos irmãos: C231 (dependência dura) · `central-conteudos-importar-perfil.md` (C230) · `central-conteudos-link-instagram.md` (C220) · `central-conteudos-ingestao.md` (C211) · `acervo-busca-por-sentido.md` (C229). +- Arquivos-pista: `src/utilities/content/contentPieceCataloging.ts` · `contentPieceJob.ts` · `contentPieceScheduler.ts` · `src/collections/ContentPiece.ts` (`curatedFields`) · `src/lib/publicFigureCatalog.ts` · `src/lib/speechFacets.ts` · `src/lib/speechGazetteer.ts` · `src/utilities/ai/themeSearchGuard.ts` · `rateLimit.ts` · `scripts/lib/e2e-affected-manifest.mjs`. +- `AGENTS.md` — convenções do repo (sem segundo cadastro de pessoa; PII; provider reservado aos agentes de design). + +## Self-score (shaping) + +1. Fatia = um outcome verificável? **Sim** — 6,5k fotos pré-catalogadas, buscáveis e com curadoria que permanece. +2. Appetite declarado e a intenção cabe? **Sim** (~2 dias eng + lote; fila de revisão/UI nova, treino de modelo e terceiro sem decisão cortados). +3. Persona + job + aceite claros sem jargão de stack? **Sim**. +4. Direção no codebase é hipótese? **Sim** — áreas e precedentes, sem schema/signature/fornecedor. +5. Zero decisões duras de engenharia no plano? **Sim** — engine, storage da descrição semântica, shape dos campos e migration ficam no plano de implementação. + +**Score: 5/5.** diff --git a/docs/plans/acervo-fotos-flickr-ingestao.md b/docs/plans/acervo-fotos-flickr-ingestao.md new file mode 100644 index 00000000..bc11d4b0 --- /dev/null +++ b/docs/plans/acervo-fotos-flickr-ingestao.md @@ -0,0 +1,91 @@ +# C231 — Acervo de fotos do Flickr — ingestão completa + +Status: rascunho +Atualizado em: 2026-09-26 +Issue: #1366 +Priority: P2 +Impeccable: A — N/A sem UI +Design UI: N/A — sem UI +Appetite: ~1 dia eng (script + inventário; sem UI); um outcome verificável — as 6.577 fotos originais do Flickr e seus metadados passam a viver no storage do Teqo, reexecutável sem duplicar e com recibo honesto +Responsável: — + +## Intenção + +O acervo de milhares de fotos do Jorge Solla vive só no Flickr — conta própria `depjorgesolla`, 6.577 fotos, criada em 2022 — fora do Teqo: sem storage próprio, sem inventário, refém de uma plataforma de terceiro. Enquanto o acervo de falas já tem esteira e a Central de Conteúdos organiza o que publicar, as fotos não têm onde morar. Antes de catalogar (C232) e publicar (C233/C234), elas precisam estar em casa: originais + metadados (data, álbuns, título/descrição/tags, geotag, EXIF) no storage do Teqo, com inventário conferível e reexecução que não duplica. + +## Persona e fluxo + +- **Persona / contexto:** coordenação técnica rodando a ingestão (mesa, uma vez agora e de novo a cada lote novo do Flickr); a consumidora final é a comunicação, que hoje não enxerga o acervo. +- **Job principal:** trazer o acervo fotográfico inteiro para o storage do Teqo, sem perder nada, sem duplicar e com um recibo que se possa conferir. +- **Fluxo desejado:** roda em dry-run → confere o que entraria → roda com confirmação explícita → originais + metadados descem para o storage → lê o recibo "novas / já existiam / falharam com motivo" e o inventário → reexecuta quando quiser, convergindo. +- **Anti-goals de produto:** não é catálogo curado nem galeria; não publica nada; não edita/saneia foto; não cria cadastro de pessoa; não altera nada no Flickr. + +## Objetivo e aceite + +- O acervo do Flickr (`depjorgesolla`) fica recuperável e inventariável no storage do Teqo: originais + metadados por foto (data, álbum(ns), título/descrição/tags do Flickr, geotag quando houver, EXIF quando houver). +- Nada se perde: cada foto termina em um de dois estados honestos — arquivada ou falha nomeada no recibo; falha nunca em silêncio e nenhum arquivo órfão. +- Reexecutar é seguro: a identidade é o id da foto no Flickr; rodar de novo não duplica, converge e reporta "novas / já existiam / falharam com motivo". +- O inventário responde sozinho "quantas vieram, quantas já existiam, quais falharam e por quê" sem abrir o Flickr. +- Guardrails: dry-run por padrão; escrever no bucket exige confirmação explícita; a CLI nunca aponta para DB/bucket de produção fora do runbook; nenhuma foto é publicada neste item; nada no Flickr é tocado. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — é operação/ingestão, não analytics: sem agregado, KPI ou superfície nova. O recibo da execução é conferência operacional (novas / já existiam / falharam), não métrica — não desbloqueia decisão de produto e não ganha painel. +- **Decisões desbloqueadas:** N/A — a decisão aqui é operacional ("o acervo está em casa? posso reexecutar?"), não numérica. +- **Forma:** N/A — sem engajamento/alcance; inventário é contagem de conferência. + +## Dados da decisão (literais) + +- Fonte: API oficial do Flickr da conta própria `depjorgesolla` (flickr.com/photos/depjorgesolla) — **6.577 fotos** confirmadas em 2026-09-26; baixar **originais**. +- Metadados a preservar por foto: data, álbum(ns), título/descrição/tags do Flickr, geotag quando houver, EXIF quando houver. +- Idempotência: identidade = **id da foto no Flickr**; reexecutar não duplica e converge. +- Storage: storage S3 do Teqo (bucket privado + proxy) — nunca disco efêmero de prod. +- Recibo por execução: "novas / já existiam / falharam com motivo" — falha nunca em silêncio; nenhum arquivo órfão. +- Guardas de escrita: dry-run por padrão + confirmação explícita para escrever no bucket (precedente `SEED_MEDIA_CONFIRM`/`MEDIA_RECOVER_CONFIRM`); CLI nunca aponta para DB/bucket de produção fora do runbook. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** script em `scripts/` no padrão dos imports idempotentes (dry-run, confirmação, relatório); storage em `src/utilities/mediaStorage.ts` + padrão das collections de upload privado (`ContentMedia`/`RecordingMedia`), fora do mapa S3 das collections públicas do `payload.config.ts`; download com teto como `downloadToFile.ts`. +- **Precedente a olhar:** `scripts/import-web-speeches.mjs` e `scripts/lib/cli.mjs` (dry-run, `assertWriteConfirm`, `ensureCachedDownload` com sha256), `scripts/recover-media.mjs` (`--dry-run/--verify/reconcile` + inventário verificável), `scripts/seed-posts.mjs` (`SEED_MEDIA_CONFIRM`, idempotência por chave), `src/utilities/speech/speechImport.ts` e `src/utilities/reels/reelPackageIngest.ts` (gravação transacional por chave natural). +- **Risco de acoplamento:** não criar segundo cadastro de pessoa; não pendurar o acervo na `media` pública (leitura anônima); não herdar o mapa S3 das collections públicas sem revisar visibilidade; egress de rede pelo proxy com allowlist já usado pelos scripts; `push: false` e migração commitada se houver schema novo. + +## Dependências + +- Nenhuma dura. C232 (catalogação) e C233/C234 (publicação) dependem deste. +- Credenciais da API do Flickr (Q1) e capacidade do bucket do homeserver (Q3) precisam estar resolvidas antes do lote. + +## Fora de escopo + +- Catalogação com IA/tags (C232); publicação (C233/C234); curadoria/edição/saneamento de imagem; álbum público e selfie; vídeos do Flickr e outras plataformas (têm donos próprios); qualquer alteração no Flickr; UI de administração do acervo. + +## Rabbit holes de produto + +- **"Já que baixa foto, baixa os vídeos do Flickr também".** Se alguém "só completar": formatos de vídeo, streaming, GBs a mais. **Corte neste item:** só fotos; vídeo tem dono próprio. +- **"Reorganiza/renomeia tudo no Flickr".** Se alguém "só completar": re-upload, perda de data/álbum, links quebrados. **Corte neste item:** baixar como está; nome/organização é decisão da catalogação (C232). +- **"Monta a UI de administração do acervo agora".** Se alguém "só completar": tela, filtros, curadoria — fora do appetite. **Corte neste item:** script + inventário; UI é C232/C233. +- **"Apaga do Flickr o que já baixou".** Se alguém "só completar": perda irreversível da fonte. **Corte neste item:** nunca; o Flickr é fonte e não se toca. + +## Questões em aberto (produto) + +- **Quem fornece as credenciais da API do Flickr e onde elas vivem?** **Opções:** A) chave de API da própria conta, provisionada pelo dono e só no env do runbook (nunca no repo) | B) OAuth do dono executado na hora | C) scraping da página pública. **Recomendação:** A — caminho oficial para conta própria, segredo fora do repo; C é proibido pelo padrão anti-scraping. _(assumido — validar com produto)_ +- **Fotos que aparecem em múltiplos álbuns duplicam?** **Opções:** A) não — dedupe pelo id já resolve e os álbuns viram metadado da mesma foto | B) uma cópia por álbum. **Recomendação:** A — uma foto, N álbuns no metadado; registrar a contagem no inventário. +- **O bucket do homeserver comporta o lote?** **Opções:** A) medir antes (quantidade × tamanho médio dos originais) e só então rodar o lote completo | B) rodar em lotes por álbum. **Recomendação:** A com verificação prévia; se apertar, B é a contingência. _(assumido — verificar antes do lote)_ +- **Existem fotos de terceiros em álbuns próprios?** **Opções:** A) inventariar com proveniência e não republicar sem revisão | B) excluir da ingestão. **Recomendação:** A — o risco é de publicação, não de arquivo: baixar para preservar e marcar para revisão futura. + +## Referências + +- GitHub Issue [#1366](https://github.com/fsolla/teqo/issues/1366) +- Design UI (gate): N/A — sem UI +- Plano irmão: C232 (catalogação do acervo — depende deste); C230 `docs/plans/central-conteudos-importar-perfil.md` (precedente de ingestão sob demanda — janela recente/dedupe por id; aqui é o oposto intencional: backfill em massa da fonte própria). +- Arquivos-pista: `src/utilities/mediaStorage.ts` · `src/payload.config.ts` (mapa S3) · `src/collections/ContentMedia.ts` e `src/collections/RecordingMedia.ts` (mídia privada) · `src/utilities/media/downloadToFile.ts` · `scripts/import-web-speeches.mjs` · `scripts/recover-media.mjs` · `scripts/seed-posts.mjs` · `scripts/lib/cli.mjs` · `src/utilities/speech/speechImport.ts` · `src/utilities/reels/reelPackageIngest.ts` +- `AGENTS.md` (storage S3, guards de escrita, `push: false`/migrações) + +## Self-score (shaping) + +1. Fatia = um outcome verificável? **Sim** — 6.577 fotos originais + metadados no storage do Teqo, reexecutável e com recibo. +2. Appetite declarado e a intenção cabe? **Sim** (~1 dia, script + inventário; UI/edição/vídeo cortados). +3. Persona + job + aceite claros sem jargão de stack? **Sim**. +4. Direção no codebase é hipótese? **Sim** — áreas/pistas, sem schema/signature. +5. Zero decisões duras de engenharia? **Sim** — collection, chave, formato de inventário e download ficam no plano de implementação. + +**Score: 5/5.** diff --git a/docs/plans/album-fotos-publico-busca-ui-design.html b/docs/plans/album-fotos-publico-busca-ui-design.html new file mode 100644 index 00000000..f1c1e314 --- /dev/null +++ b/docs/plans/album-fotos-publico-busca-ui-design.html @@ -0,0 +1,668 @@ + + + + + + + Design — C233 · Álbum público de fotos + + + + + +
+
+
+ C233 · gate hi-fi + Rota pública · /fotos +
+

+ Álbum público: encontrar a foto certa sem virar rede social +

+

+ Cidadão procura por termo, data, município, atividade ou pessoa pública; vê somente fotos + aprovadas e entende o contexto antes de guardar a imagem. +

+
+ + +
+

Cena 01

+

+ Desktop ~1280 · cabeçalho, busca, facetas e grade contextual +

+
+
+
+
+
+ Jorge Solla +
+
+ InícioFotosConteúdos +
+
+
+
+
+
+
+

+ Memória da nossa caminhada +

+

+ Fotos que contam onde a gente esteve. +

+

+ Procure uma agenda, um município ou uma pessoa pública e abra cada registro com + data e contexto. +

+
+ Encontre você nas fotos +
+
+
+
+ +
+
+ +
+ +
+
+ + + + + +
+
+
+
+

+ Agenda em destaque +

+

+ Plenárias e encontros no município +

+
+ Mais recentes primeiro +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ + +
+

Cena 02

+

+ Mobile ~390 · grade em 2 colunas e filtros em bottom sheet +

+
+
+
+
+ Jorge Solla +
+ Fotos +
+
+

+ Nossa caminhada +

+

+ Encontre um momento. +

+

+ Busque pela agenda, pelo lugar ou por quem apareceu. +

+ Encontre você nas fotos +
+
+
+ Agenda, município ou pessoa… +
+
+ +
+
+
+
+

Plenária pela saúde

+

+ 12 set · Município · Plenária +

+

Jorge Solla e pessoa convidada

+
+
+
+

Visita à unidade

+

+ 08 set · Município · Visita +

+

Jorge Solla

+
+
+
+

Encontro local

+

+ 03 set · Município · Reunião +

+

Jorge Solla e pessoa convidada

+
+
+
+

Caminhada no centro

+

+ 28 ago · Município · Caminhada +

+

Jorge Solla

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

+ Filtros +

+

Refine sua busca

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

Cena 03

+

+ Foto aberta em contexto · detalhe sem mecânicas sociais +

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

Cena 04

+

+ Vazio honesto · nada parecido ocupa a grade +

+
+
+
+ +
+

Nada encontrado com esses filtros

+

+ Tente outro termo ou volte a ver todas as fotos aprovadas do álbum. +

+
+ Busca: “termo informado”Município selecionadoAtividade selecionada +
+ +
+
+
+ + +
+

Cena 05

+

+ Canal de remoção discreto · rodapé do álbum +

+
+
+
+

Aparece em alguma foto?

+

+ Se você não quiser que ela fique pública, fale com a equipe responsável pelo acervo. +

+
+ Pedir remoção de uma foto +
+
+
+
+ Jorge Solla 1313 +

Deputado Federal · PT · Bahia

+
+
+ FotosPrivacidadeContato +
+
+
+
+
+
+ + diff --git a/docs/plans/album-fotos-publico-busca.md b/docs/plans/album-fotos-publico-busca.md new file mode 100644 index 00000000..387c82fd --- /dev/null +++ b/docs/plans/album-fotos-publico-busca.md @@ -0,0 +1,111 @@ +# C233 — Álbum público de fotos com busca por data, local, atividade e pessoa pública + +Status: rascunho +Atualizado em: 2026-09-26 +Issue: #1368 +Priority: P2 +Impeccable: C — fluxo/rota pública nova (`/fotos`) +Design UI: docs/plans/album-fotos-publico-busca-ui-design.html +Appetite: ~1–2 dias eng; um outcome verificável — o cidadão chega à foto certa por data, município, atividade, pessoa pública ou termo, e só vê o que a curadoria aprovou +Responsável: — + +## Intenção + +O acervo de fotos do mandato está sendo montado e catalogado (C231/C232), mas não tem porta pública: quem viu Solla num comício, numa plenária, numa obra ou numa reunião — ou quem procura o registro de uma agenda — não tem onde navegar. O pedido do dono é transformar o acervo num álbum público do mandato: buscar por data, local (município), atividade (ex.: comício, plenária, reunião, obra) e por pessoa pública que aparece na foto — e chegar à foto que procura. Sem reconhecimento facial nesta fatia (C234); só entra o que a curadoria aprovar; e qualquer pessoa pode pedir a remoção de foto em que aparece. + +## Persona e fluxo + +- **Persona / contexto:** cidadão/eleitor no celular (apoiador, morador do município, alguém que esteve no evento), em estado de procura leve — quer ver/relembrar a foto, não estudar o acervo. +- **Job principal:** achar a foto certa por data, município, atividade ou pessoa que aparece — e, chegando nela, entender o contexto real (quando, onde, o quê, quem). +- **Fluxo desejado:** entra no álbum → navega por capítulos/álbuns (evento, data, município) ou já busca/filtra por data, município, atividade e pessoa pública (ou digita um termo) → vê a grade com legenda real (data · local · atividade · quem aparece) → abre a foto em contexto → nada casa = estado vazio explicando e oferecendo limpar filtros → se aparece numa foto, o canal "é você nesta foto? peça a remoção" está visível. +- **Anti-goals de produto:** não é rede social (sem like/comentário/share com PII); não é dashboard; não expõe foto não aprovada; não cria segundo cadastro de pessoa (`Contact`); não é a busca facial (C234). + +### Esboço de fluxo (C) + +```text +[site] → /fotos + → capítulos/álbuns (evento · data · município) e/ou facetas: data, município, atividade, pessoa pública + termo + → grade de fotos aprovadas (legenda real: data · local · atividade · quem aparece) + → abre a foto em contexto → chega à foto que procura + → nada casa = vazio honesto (explica + limpar filtros) + → "é você nesta foto? peça a remoção" → atendimento humano → foto sai do público e do índice +[outcome: a foto certa alcançada em poucos toques, só com o que foi aprovado] +``` + +### Design UI (C) + +- Design UI (gate): `docs/plans/album-fotos-publico-busca-ui-design.html` + +## Objetivo e aceite + +- O visitante acha foto por data, município, atividade e pessoa pública (facetas single-value combináveis) e por termo — e chega à foto. +- Só fotos aprovadas aparecem; foto não aprovada não é acessível nem por URL direta (fail-closed). +- Pessoa pública só pelo catálogo curado, por nome canônico — nunca `Contact`, nunca nome inferido por rosto. +- Foto mostra contexto real (data, local, atividade, quem aparece); nada inventado. +- Vazio honesto: sem resultado = estado que explica e sugere limpar filtros; nunca preencher com "parecidas". +- Remoção a pedido: canal visível; após atendimento humano registrado a foto some do público e do índice de busca; sem esse registro, não republica (fail-closed, right to erasure). +- Cache/revalidação por tag: edição de curadoria reflete no site; pull-down de foto/álbum é imediato. +- Acessibilidade: grade com `alt` real (descrição curada), navegação por teclado, foco visível e contraste; mobile primeiro. +- Performance: grade leve no celular (miniaturas, carregamento sob demanda); imagens same-origin pelo proxy de mídia do Teqo — bucket privado, sem hotlink. +- Guardrail eleitoral: pull-down de foto/álbum não depende de deploy; abrir a rota é decisão do gate (ver Questões). + +## Dados (intenção) + +- **Vou apresentar dados?** Não — a superfície é busca/navegação de acervo, não analytics: nenhum número, contador ou ranking aparece para o visitante. +- **Decisões desbloqueadas:** N/A — a decisão do visitante é qualitativa ("esta é a foto que eu procurava?"); nenhuma escolha numérica nomeável. +- **Forma:** N/A — restrição de produto: proibido contador de vaidade ("mais vistas", "populares") ou métrica de engajamento na superfície; qualquer medição interna, se houver, é anônima e não aparece no site. + +## Dados da decisão (literais) + +- Rota pública nova: **`/fotos`** (literal proposto; o gate confirma) — contrato de URL público, canônico e indexável; facetas single-value na URL no padrão de `contentPieceCatalog` (data, município, atividade, pessoa pública) + busca textual. +- **Sem reconhecimento facial** nesta fatia; busca por **pessoa pública** só pelo catálogo curado (nome canônico; nunca `Contact`, nunca nome inferido por rosto). +- **Só entra no público o que a curadoria aprovar** (estado de publicação explícito) — acervo bruto nunca vaza. +- **Remoção a pedido:** canal visível "é você nesta foto? peça a remoção" com atendimento humano; foto removida some do público e do índice de busca (right to erasure) — fail-closed: sem atendimento registrado, não republica. +- Imagens servidas same-origin pelo proxy de mídia do Teqo (bucket permanece privado); nada de hotlink para Flickr. +- Vazio honesto: sem resultado = estado explicando e sugerindo limpar filtros; nunca preencher com "parecidas". +- Cache público com revalidação por tag (edição de curadoria reflete no site); pull-down de foto/álbum precisa ser imediato. +- **Janela eleitoral (eleição 04/10/2026):** registrar a questão de timing — publicar a rota antes ou depois da eleição / atrás de gate de curadoria com pull-down imediato. Recomendação do plano: **não abrir superfície pública nova nos dias finais de campanha; tratar C233/C234 como pós-eleição**, mantendo C231/C232 internas. É pergunta do gate, não bloqueio do plano. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** rota nova em `src/app/(frontend)/` (`/fotos`) com componentes públicos próprios; leitura pública cacheada no padrão de `src/utilities/content/contentPieceReads.ts`; contrato puro de URL/facetas/view model no padrão de `src/lib/contentPieceCatalog.ts`; mídia pelo proxy existente das portas de mídia privada; tag de cache registrada no dono da allowlist de revalidação (`src/utilities/revalidateRequest.ts`). +- **Precedente a olhar:** `/conteudos` (`page.tsx`, `loading.tsx`, estados `ContentPieceEmptyState`/`ContentPieceNoResults`); facetas/URL internas `src/utilities/speech/speechListUrl.ts` e `src/lib/speechFacets.ts`; design de facetas `docs/plans/acervo-paridade-busca-filtros-ui-design.html`; visibilidade eleitoral fail-closed (`hidden`/`isPostVisible`, `AGENTS-public.md`). +- **Risco de acoplamento:** contrato de URL público é congelado por AGENTS — canônico/indexável e facetas single-value no vocabulário existente; tag nova de revalidação exige editar a allowlist fechada; imagem pública passa pelo proxy same-origin e pela allowlist do otimizador do Next; não tocar em `Contact`; módulo utilitário novo de topo quebra o pin de convenções (`tests/unit/codebaseConventions.unit.spec.ts:421-427`); pull-down eleitoral não pode depender de deploy. + +## Dependências + +- **Duras:** C232 (catálogo com atividade/local/pessoas — sem esses campos não há facetas) e C231 (acervo — sem acervo curado não há foto para publicar). Nenhuma das duas entra aqui. +- **Soft:** C234 (reconhecimento facial) é o sucessor declarado, fora desta fatia. + +## Fora de escopo + +- Reconhecimento facial (C234); upload público; edição de imagem. +- Analytics de vaidade / contador de visualizações. +- App/mobile nativo; reescrita da home. + +## Rabbit holes de produto + +- **Álbuns por evento mantidos à mão.** Se alguém "só completar": curadoria dupla (álbum + foto) e álbuns vazios por falta de gesto. **Corte neste item:** capítulos/álbuns derivados do catálogo curado, sem segunda curadoria paralela. +- **Lightbox social (like/comentário/compartilhar com PII).** Se alguém "só completar": o álbum vira rede social e superfície de moderação. **Corte neste item:** sem reações nem comentário; quem aparece é dado de legenda/filtro, não perfil. +- **Busca por conteúdo dentro da foto ("acha a faixa, a placa").** Se alguém "só completar": visão computacional entra aqui — já é C232. **Corte neste item:** esta busca consome os campos que C232 produz; aqui não se infere nada. +- **Sitemap de 6,5k páginas de foto.** Se alguém "só completar": cada foto vira página indexável e o SEO explode. **Corte neste item:** canônico/indexável é a rota do álbum com facetas; foto avulsa não ganha página própria nesta fatia. + +## Questões em aberto (produto) + +- **Quando abrir a superfície?** **Opções:** A) pós-eleição (04/10), com C231/C232 internas | B) antes, atrás de gate de curadoria com pull-down imediato | C) publicar agora sem ressalva. **Recomendação:** A — não abrir superfície pública nova nos dias finais de campanha; tratar C233/C234 como pós-eleição. _(assumido — validar com produto)_ +- **Qual URL?** **Opções:** A) `/fotos` (proposto) | B) `/galeria` | C) `/acervo`. **Recomendação:** A — curto, em pt-BR e descreve o conteúdo; `/acervo` colide com o acervo interno de falas e `/galeria` é genérica; o gate confirma. _(assumido — validar com produto)_ +- **Foto avulsa ou álbuns/capítulos por evento?** **Opções:** A) os dois níveis — navegação por álbum e busca que chega à foto | B) só foto avulsa | C) só álbuns. **Recomendação:** A — a foto é a unidade do resultado, mas capítulos dão contexto de evento e ajudam quem não sabe o que procura. _(assumido — validar com produto)_ +- **Pessoa pública aparece com nome ou como filtro "aparições"?** **Opções:** A) nome canônico visível na legenda e como filtro | B) só filtro "pessoas que aparecem", sem nomear | C) sem faceta de pessoa. **Recomendação:** A — é a busca pedida pelo dono e o nome vem do catálogo curado; o canal de remoção é o contrapeso. _(assumido — validar com produto)_ + +## Referências + +- GitHub Issue [#1368](https://github.com/fsolla/teqo/issues/1368) +- Design UI (gate): `docs/plans/album-fotos-publico-busca-ui-design.html`. +- Dependências: C231 (acervo) e C232 (catálogo com atividade/local/pessoas). +- Precedentes: `docs/plans/acervo-busca-por-sentido.md`, `docs/plans/central-conteudos-importar-perfil.md`, `docs/plans/acervo-paridade-busca-filtros-ui-design.html`. +- Arquivos-pista: `src/lib/contentPieceCatalog.ts` · `src/utilities/content/contentPieceReads.ts` · `src/app/(frontend)/conteudos/(catalog)/page.tsx` · `src/app/(frontend)/conteudos/[slug]/midia/route.ts` · `src/utilities/revalidateRequest.ts` · `src/utilities/speech/speechListUrl.ts` · `src/lib/speechFacets.ts`. +- `AGENTS.md` (contrato de URL público, mídia same-origin) · `AGENTS-public.md` (visibilidade eleitoral fail-closed). + +## Self-score (shaping) + +5/5 — (1) fatia = um outcome verificável (achar a foto por data, município, atividade, pessoa ou termo, só com aprovadas); (2) appetite ~1–2 dias comporta a rota pública sobre o catálogo de C232, com facetas, busca, vazio, remoção e cache, sem construir o acervo; (3) persona, job e aceite verificáveis, incluindo acessibilidade; (4) direção no codebase é hipótese com precedentes nomeados; (5) zero decisão dura de engenharia (a rota literal é decisão de produto sujeita ao gate; schema, migration, cache e modelagem ficam no plano de implementação). diff --git a/docs/plans/busca-fotos-por-selfie-ui-design.html b/docs/plans/busca-fotos-por-selfie-ui-design.html new file mode 100644 index 00000000..66431751 --- /dev/null +++ b/docs/plans/busca-fotos-por-selfie-ui-design.html @@ -0,0 +1,680 @@ + + + + + + + Design — C234 · Busca de fotos por selfie + + + + + +
+
+
+ C234 · gate hi-fiFluxo sensível · LGPD fail-closed +
+

+ Encontre você nas fotos — privado, explícito e sem placar de semelhança +

+

+ A pessoa parte do álbum, entende o uso de biometria, escolhe a própria selfie e recebe + apenas fotos públicas aprovadas em que aparece. A selfie permanece no dispositivo. +

+
+ + +
+

Cena 01

+

+ Desktop ~1280 · entrada no contexto da /fotos +

+
+
+
+
+
+ Jorge Solla +
+ Fotos +
+
+
+ +
+
+

+ Álbum público +

+

+ Procure uma foto por data, lugar ou atividade. +

+

+ Use os filtros para navegar pelos registros aprovados da caminhada. +

+
+ Buscar no álbum… +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + +
+

Cena 02

+

+ Desktop ~1280 · aviso de biometria e consentimento explícito +

+
+
+
+
+ +
+ +
+

+ Antes da sua selfie +

+

Sua face é um dado biométrico sensível

+

+ Com sua autorização, comparamos a sua selfie com o índice permitido do álbum para + mostrar somente fotos públicas aprovadas em que você aparece. +

+
+
+ +

+ A selfie não sai do dispositivo.
A imagem é processada aqui e não é guardada na galeria do site. +

+
+
+ +

+ Você pode desistir e pedir remoção.
O resultado não mostra nomes de terceiros nem percentual de semelhança. +

+
+
+ +

+ Saiba como tratamos seus dados na + Política de Privacidade. +

+ + +
+
+
+ + +
+

Cena 03

+

+ Mobile ~390 · captura ou envio, com processamento local evidente +

+
+
+ Encontre você +
+
+
+ +
+

+ Passo 2 de 3 +

+

Escolha uma selfie nítida

+

+ Olhe para a câmera, com o rosto bem iluminado e sem outras pessoas na imagem. +

+
+
+ Prévia no aparelho +
+
+ +

+ Esta foto não sai do seu dispositivo.
O processamento acontece aqui. +

+
+ + +
+
+
+ + +
+

Cena 04

+

+ Mobile ~390 · processando sem promessas ou percentuais +

+
+
+ Encontre você +
+
+
+
+
+
+
+
+

Procurando você nas fotos aprovadas…

+

+ Mantenha esta tela aberta. Sua selfie continua somente neste aparelho. +

+
+ Sem upload da imagem · sem + cadastro +
+
+
+
+ + +
+

Cena 05

+

+ Desktop ~1280 · resultado mínimo: só fotos aprovadas em que você aparece +

+
+
+
+
+
+ Jorge Solla +
+ +
+
+
+
+
+

+ Sua busca por selfie +

+

+ Estas são as fotos em que encontramos você. +

+

+ Mostramos apenas registros públicos aprovados. Não exibimos nomes de outras + pessoas nem nota de semelhança. +

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

Quer controlar sua presença no álbum?

+

+ Saia do índice ou peça a remoção de uma foto. +

+
+ Gerenciar minha presença +
+
+
+
+
+ + +
+

Cena 06

+

+ Mobile ~390 · vazio honesto, sem “parecidos” +

+
+
+ Resultado +
+
+
+ +
+

Não encontramos você

+

+ Talvez a luz ou o ângulo tenham dificultado a busca — ou ainda não haja uma foto + pública aprovada sua no álbum. +

+

+ Não mostramos pessoas parecidas para preencher a tela. +

+ + Voltar ao álbum +
+
+
+ + +
+

Cena 07

+

+ Fail-closed · consentimento não configurado, fluxo indisponível +

+
+
+
+ +
+

+ Proteção de dados +

+

+ A busca por selfie está indisponível +

+

+ O texto de consentimento necessário ainda não está configurado. Por segurança, não + podemos receber nem processar sua selfie agora. +

+

+ Nenhuma imagem foi capturada ou enviada. +

+ Voltar ao álbum de fotos +
+
+
+ + +
+

Cena 08

+

+ Mobile ~390 · opt-out e pedido de remoção com confirmação +

+
+
+
+ Minha presença +
+
+

+ Privacidade +

+

Você decide se quer aparecer

+

+ Escolha o pedido. A equipe registra o atendimento e mantém a proteção fechada até + concluir. +

+ + + Cancelar +
+
+ +
+
+
+
+ +
+

Confirmar saída do índice?

+

+ Vamos registrar seu pedido. Até o atendimento ser concluído, sua presença permanece + protegida e não deve voltar ao índice. +

+ + +
+
+
+
+
+ + diff --git a/docs/plans/busca-fotos-por-selfie.md b/docs/plans/busca-fotos-por-selfie.md new file mode 100644 index 00000000..26b629bc --- /dev/null +++ b/docs/plans/busca-fotos-por-selfie.md @@ -0,0 +1,106 @@ +# C234 — Busca por selfie — visitante encontra as fotos em que aparece + +Status: rascunho +Atualizado em: 2026-09-26 +Issue: #1369 +Priority: P2 +Impeccable: C — fluxo público novo (busca por selfie na área pública de fotos) +Design UI: docs/plans/busca-fotos-por-selfie-ui-design.html +Appetite: ~2–3 dias eng + aval jurídico (produto); um outcome verificável — com consentimento ativo, o visitante encontra no acervo público aprovado as fotos em que aparece, sem que a selfie saia do dispositivo e sem score +Responsável: — + +## Intenção + +Quem compareceu a um evento ou plenária com Jorge Solla quer se achar no acervo — hoje as fotos aprovadas vivem em `/fotos` (C233), mas encontrar-se no meio de centenas é garimpo manual. O pedido do dono é direto: a pessoa tira/envia uma foto própria e vê as fotos públicas em que aparece — com consentimento explícito, sem nomes de terceiros e sem score de semelhança. Reconhecimento facial é permitido e comum em eventos/festas; o desenho tem de ser fail-closed em consentimento (exigência travada do repo) e processar o mínimo possível. É dependente por natureza: sem o acervo catalogado e aprovado (C231/C232) e a superfície `/fotos` (C233), não há o que buscar. Como o tema é biometria de face — dado sensível —, o appetite embute aval jurídico e DPIA como dependência de produto, com a eleição de 04/10/2026 no calendário. + +## Persona e fluxo + +- **Persona / contexto:** visitante que foi a um evento com Solla, no celular, curioso para se ver no acervo, sem conta na campanha. +- **Job principal:** encontrar, entre as fotos públicas aprovadas, as que eu apareço. +- **Fluxo desejado:** abre `/fotos` → toca "Encontre você nas fotos" → lê o aviso (biometria/LGPD) e consente; sem consentimento configurado o fluxo nem abre → tira/envia uma selfie → o reconhecimento roda no dispositivo (a selfie não sobe) → vê só as fotos aprovadas em que aparece, sem nome de terceiros e sem score → decide se baixa/compartilha → a qualquer momento pede para sair do índice e/ou despublicar uma foto, e o pedido fica registrado. +- **Anti-goals de produto:** não é vigilância nem CRM de rostos; não identifica terceiros; não cruza com `Contact`/leadership; não oferece busca por foto de outra pessoa; não abre sem consentimento; não vira feature social. + +### Esboço de fluxo (C) + +```text +[fotos] → "Encontre você nas fotos" → aviso + consentimento explícito + → sem consentimento ativo: recusa clara (fail-closed), fim + → tira/envia selfie → reconhecimento no dispositivo (a selfie não sai daqui) + → resultado: só as fotos aprovadas em que a pessoa consultante aparece (sem terceiros, sem score) + → remoção: sair do índice / despublicar foto → atendimento registrado +``` + +### Design UI (C) + +- Design UI (gate): `docs/plans/busca-fotos-por-selfie-ui-design.html` — por que C: superfície pública nova (permissão/captura, estados de consentimento, resultado, vazio honesto, remoção), nas cenas 390/1280; o HTML hi-fi é o registro do aceite e a fonte de verdade do port. + +## Objetivo e aceite + +- Com consentimento ativo, o visitante tira/envia uma selfie e recebe somente as fotos do acervo público aprovado em que aparece. +- Sem consentimento ativo (texto aprovado não configurado), o fluxo recusa com linguagem clara — nunca meio aberto, nem na UI nem no servidor. +- Nenhum rastro da selfie no servidor: por padrão a imagem não sobe; se a implementação escolher upload consentido, retenção zero documentada após o match. +- Remoção/opt-out funciona: sair do índice e despublicar fotos a pedido, com atendimento registrado; fail-closed até atender. +- Nenhum score, percentual ou nome de terceiro em nenhum estado — nada de "outras pessoas parecidas". +- Antiabuso: limite de tentativas anônimas, sem criação de conta obrigatória. +- O resultado é o mesmo acervo aprovado para o público pela régua do C232/C233 — nenhuma foto privada/bruta abre porta lateral. +- **Guardrails:** Consent/LGPD fail-closed (conceito travado); sem cruzamento com `Contact`/leadership; biometria não vira cadastro de pessoa. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — o resultado é "quais fotos", nunca "quão parecido". Score/percentual de semelhança ("match 87%") é anti-goal explícito do dono, não um dado a formatar. +- **Decisões desbloqueadas:** N/A — a escolha do visitante ("essa foto é minha, quero guardar/compartilhar") é qualitativa; nenhum ator decide a partir de número. +- **Forma:** N/A — restrição de produto: **sem score/percentual** de semelhança em nenhum estado da superfície; a única saída é a lista de fotos. + +## Dados da decisão (literais) + +- **Consentimento fail-closed:** sem Consent ativo (resolvido por `key` estável, com texto versionado e hash) o fluxo não habilita — nem na UI, nem no servidor. Texto/chave exatos são da implementação, o conceito é travado. +- **Escopo do índice facial — pergunta central do gate.** Opções: (A) **só consentidos/catálogo curado** — indexa rostos apenas de quem aderiu (equipe, lideranças, figuras públicas) e a busca por selfie só devolve se o rosto consultante já estiver indexado (mais restrito, mais seguro, UX pior); (B) **índice de todos os rostos do acervo público aprovado**, mas a resposta só se refere à própria pessoa consultante — sem nomes de terceiros, sem listar outras pessoas, com DPIA + aval jurídico e mecanismo de remoção do índice; (C) não indexar rostos anônimos e só habilitar busca para pessoas previamente cadastradas com consentimento. **Recomendação do plano:** A/C no MVP (falha fechada), evoluindo para B somente com aval jurídico documentado e DPIA — o gate decide. +- **Selfie nunca sai do dispositivo por padrão:** detecção/embedding facial no cliente (precedente de visão on-device do repo); ao servidor vai só o vetor, sem imagem — se a opção de upload consentido for escolhida, retenção zero após o match e nunca armazenar em `media` pública. +- **Resposta mínima:** mostra só as fotos aprovadas em que a pessoa consultante aparece; nunca "outras pessoas parecidas", nunca nome de terceiro, nunca score. +- **Remoção:** pessoa pode pedir para sair do índice e ter fotos despublicadas; atendimento registrado; fail-closed até atender. +- **Nada de foto privada/bruta** no resultado: só acervo aprovado para o público (mesma régua do C233). +- **Antiabuso:** limite de tentativas anônimas (rate limit), sem criação de conta obrigatória. +- **Janela eleitoral (eleição 04/10/2026) e DPIA:** superfície pública de biometria não abre sem revisão jurídica; registrar como dependência de produto e timing pós-eleição (o gate decide). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** superfície `/fotos` do C233 (rota + componentes), um fluxo client-side para captura/embedding (precedente `src/components/cards/`), `src/utilities/` para consentimento por key, rate limit e a rota de consulta; qualquer arquivo de selfie, se existir, atrás do gate privado padrão. +- **Precedente a olhar:** `src/components/cards/cardCutout.ts` (visão on-device; a foto nunca sai do navegador), `src/utilities/campaignConsent.ts` + `src/lib/campaignConsentKeys.ts` (Consent por key fail-closed), `src/utilities/privateMedia/` + `src/app/(frontend)/conteudos/[slug]/midia/route.ts` (arquivo privado atrás de gate), `src/utilities/ai/rateLimit.ts` (antiabuso anônimo), `src/utilities/sameOriginRequest.ts` (POST público). +- **Risco de acoplamento:** vocabulário colide — "biometria" no repo hoje é WebAuthn/passkeys (`src/utilities/campaignBiometricsPrompt.ts`), não face. O gate de consentimento e a régua de publicação (C232/C233) são donos; esta feature não cria segunda régua nem segundo cadastro de pessoa. Índice facial é infra própria (o C229 limita embeddings ao acervo interno de falas — implementação decide o como). + +## Dependências + +- Duras: C231 (acervo de fotos), C232 (catálogo/aprovação), C233 (superfície pública `/fotos`). +- Duras de produto: aval jurídico + DPIA antes de expor superfície pública de biometria; timing pós-eleição (04/10/2026). +- Soft: C229 (`docs/plans/acervo-busca-por-sentido.md`) — precedente de índice próprio, abordagem fica na implementação. + +## Fora de escopo + +- Indexação biométrica de vídeos/gravações; moderação automática; API pública de reconhecimento; app nativo. +- Nomeação/identificação de terceiros; galeria "quem é quem"; cruzamento com `Contact`/leadership; qualquer mecânica social (seguir/curtir/perfil público). + +## Rabbit holes de produto + +- **"Só completar" com identificação de todo mundo.** Se alguém "só completar": nomear automaticamente cada rosto do acervo — virou vigilância/CRM de rostos. **Corte neste item:** só as fotos da pessoa consultante; nunca nome de terceiro, nunca diretório de rostos. +- **Upload ilimitado de selfies / galeria de selfies.** Se alguém "só completar": guardar selfies para "melhorar o match". **Corte neste item:** por padrão a selfie não sobe; sem galeria, sem retenção de imagem. +- **Face matching em tempo real.** Se alguém "só completar": busca ao vivo no evento, fila de câmeras. **Corte neste item:** busca assíncrona sob demanda dentro da `/fotos`. +- **Shareability social.** Se alguém "só completar": ranking/feed de "fotos mais parecidas". **Corte neste item:** resultado privado da consulta, sem métrica e sem exposição. + +## Questões em aberto (produto) + +- **Escopo do índice facial (pergunta central do gate)?** **Opções:** A) só consentidos/catálogo curado | B) todos os rostos do acervo público aprovado, com resposta só sobre a própria pessoa + DPIA/aval | C) só pessoas previamente cadastradas com consentimento. **Recomendação:** A/C no MVP (falha fechada); B só com aval jurídico documentado e DPIA — o gate decide. +- **Quem opera a fila de remoção/atendimento?** **Opções:** A) comunicação/assessoria (dona do acervo), com registro no fluxo interno | B) coordenação de campanha | C) jurídico. **Recomendação:** A — quem publica/despublica atende; jurídico entra na revisão, não na fila. _(assumido — validar com produto)_ +- **Retenção do vetor de quem consulta?** **Opções:** A) zero — descartado ao fim da consulta | B) opt-in explícito do visitante para entrar no índice | C) retenção curta para antiabuso. **Recomendação:** A como padrão e B só como opt-in no escopo A/C; C rejeitada — antiabuso é contador, não biometria guardada. +- **Revisão jurídica/DPIA é dependência dura?** **Opções:** A) DPIA + aval registrados antes de qualquer superfície pública | B) aval só para o MVP restrito (A/C) | C) abrir sem revisão. **Recomendação:** A/B — sem revisão registrada não abre; o gate decide o timing (eleição 04/10/2026). + +## Referências + +- GitHub Issue [#1369](https://github.com/fsolla/teqo/issues/1369) +- Design UI (gate): `docs/plans/busca-fotos-por-selfie-ui-design.html` +- `docs/plans/acervo-busca-por-sentido.md` (C229 — índice próprio; implementação decide) +- `src/components/cards/cardCutout.ts` (precedente on-device) · `src/utilities/campaignConsent.ts` + `src/lib/campaignConsentKeys.ts` (Consent fail-closed) · `src/utilities/privateMedia/` + `src/app/(frontend)/conteudos/[slug]/midia/route.ts` (privado atrás de gate) · `src/utilities/ai/rateLimit.ts` (antiabuso) +- `AGENTS.md` — Consent/LGPD fail-closed e convenções travadas. + +## Self-score (shaping) + +5/5 — (1) fatia = um outcome verificável (com consentimento, achar-se nas fotos aprovadas; sem ele, recusa); (2) appetite ~2–3 dias + aval jurídico comporta consentimento, captura on-device, resultado, remoção e antiabuso, com índice/storage no plano de implementação; (3) persona, job e aceite sem jargão de stack; (4) direção no codebase é hipótese com precedentes nomeados; (5) zero decisão dura de engenharia (escopo do índice, vetor, rate limit e storage ficam para a implementação, com o gate decidindo o escopo).