Skip to content

Feat/refinamento de busca#5

Merged
bob-reis merged 18 commits into
mainfrom
feat/refinamento-de-busca
Sep 19, 2025
Merged

Feat/refinamento de busca#5
bob-reis merged 18 commits into
mainfrom
feat/refinamento-de-busca

Conversation

@bob-reis

Copy link
Copy Markdown
Owner

Descrição

melhoria no visual dos resultados

Escopo da Mudança

  • Código da API/Engine
  • UI/UX (inclua screenshots/gifs)
  • Manifesto de sites (docs/sites.core.yaml)
  • Documentação (docs/*)

Checklist de Qualidade (Architect)

  • Lint e typecheck passam (pnpm lint, pnpm typecheck)
  • Testes unit/contract/e2e passam e cobertura mantida (≥ 85% no core)
  • Contrato SSE estável (site_start, site_result, progress, done)

Segurança (Agent Smith / Neo / Trinity)

  • Entrada validada (regex/allowlist por site), sem SSRF
  • Sem persistência de dados; logs sem PII
  • Semgrep e audit sem achados alto/crit
  • Nenhum segredo no código (Gitleaks)
  • Threat model revisado se superfícies mudaram

Notas de Implementação

  • Para telas de recuperação: 1 tentativa, sem seguir links, apenas parsing da página inicial
  • Identificadores mascarados rotulados corretamente

Outras Observações

  • Issues relacionadas: #
  • Screenshots/Anexos:
image

      - New apps/web/lib/meta.ts: extractMeta(html, baseUrl) pega:
      - Avatar: `og:image`, `twitter:image`, JSON‑LD `image` (resolve URL relativa).
      - Título: JSON‑LD `name` → `og:title` → `<title>`.
      - Descrição: `og:description` → `meta[name=description]`.
  - Engine + tipos:
      - apps/web/lib/types.ts: SiteResult agora tem metadata?: { image?, title?, description? }.
      - apps/web/lib/engine.ts: em todos os retornos “found” com HTML disponível, anexa metadata via extractMeta. Eventos SSE incluem metadata.
      - apps/web/types/index.ts: SiteEvent.site_result e MindmapItem passam a carregar metadata. MindmapPreviewProps aceita showPreviews?.
  - UI (lateral, opt-in):
      - apps/web/components/ResultsScreen.tsx: toggle “Pré‑vias” (padrão OFF, só no layout lateral).
      - apps/web/components/SideMindmap.tsx: prop showPreviews repassada a grupos/itens.
      - apps/web/components/SideMindmapItem.tsx: exibe avatar (24x24) à esquerda quando status==='found', showPreview ativo e metadata.image disponível.
      - CSP: apps/web/middleware.ts permite img-src 'self' https: data: para imagens remotas seguras.
  - Integração de dados:
      - apps/web/app/page.tsx: mapeia metadata dos eventos para itemsAll/itemsFocus.
  - Tests e cobertura:
      - apps/web/tests/meta.spec.ts: cobre extractMeta e resolução de URLs relativas.
      - apps/web/tests/export.spec.ts: adiciona casos com vírgula e quebra de linha nos campos CSV.
      - apps/web/tests/ui.spec.ts: mais casos para URLs relativas/sem esquema e esquemas não-http(s); evita hotspot javascript:.

- Tooltips nos itens confirmados (layout lateral):
      - apps/web/components/SideMindmapItem.tsx:
      - Envolve o conteúdo em um `Tooltip` quando `status === 'found'` e existe `metadata.title` ou `metadata.description`.
      - Mostra título em negrito e descrição curta no tooltip.
      - Mantém o link clicável e o avatar (quando “Pré‑vias” está ON).
  - Já feito na etapa anterior:
      - Parser de metadados extractMeta (og/twitter/json‑ld).
      - Engine envia metadata somente nos “found”.
      - Toggle “Pré‑vias” no ResultsScreen (padrão OFF).
      - CSP ajustado para img-src 'self' https: data:.

- apps/web/components/MindmapPreview.tsx
      - Tooltip dos nós “found” agora inclui:
      - Título (em negrito) quando disponível.
      - Descrição curta (texto secundário).
      - Mantém plataforma, status, heurístico e link “Abrir”.
  - Mapa radial removido da tela:
      - ResultsScreen não importa mais MindmapPreview e sempre renderiza o SideMindmap.
  - Filtros simplificados:
      - Mantém só: Foco, Todos, Encontrado, Inconclusivo.
      - Tipos atualizados em apps/web/types/index.ts (ResultsFilter).
  - Pré‑vias sempre ativas:
      - Removi o switch de “Pré‑vias”.
      - SideMindmap recebe showPreviews sempre ligado; avatares aparecem nos itens “Encontrado”.

  Arquivos tocados

  - apps/web/components/ResultsScreen.tsx
  - apps/web/types/index.ts
      - apps/web/components/ResultsScreen.tsx: retirei os cases “not_found” e “error” do switch que monta items, alinhando com os filtros restantes: focus, all, found, inconclusive.
      - Para Instagram, além do critério anterior (canonical/og:url batendo com o perfil), adicionei um fallback robusto:
      - Extrai metadados da página (og:image, og:title via `extractMeta`).
      - Se existir imagem (og:image) e o título contiver o @username ou o username, classifica como found.
  - Mantém as evidências e anexa os metadados quando classifica como found, de modo que o avatar apareça na UI e sirva de confirmação visual.

  Com isso, o caso como “https://www.instagram.com/robertsonreis/” tende a virar “Encontrado” (verde) pois a página exibe og:image do avatar e título no formato “(... @robertsonreis ...)”.

  Se quiser, posso rodar um teste manual local com esse usuário, mas dado o ambiente restrito, recomendo:

  - Rodar a aplicação (pnpm dev), buscar “robertsonreis”, e verificar se:
      - O item Instagram está verde.
      - O avatar aparece no mapa lateral com Pré‑vias (agora sempre ativo).
      - O tooltip mostra título/descrição.
      - apps/web/lib/engine.ts:
      - Não retorna mais cedo quando detecta o redirect para login com username; guarda uma evidência inicial (final_url) e segue para baixar o HTML uma vez (como já fazemos para os outros sites).
      - Após obter o HTML:
        - Se canonical/og:url confirmar o perfil → found com metadata (avatar, título, desc).
        - OU se existir `og:image` e o título contém o username/@username OU já tínhamos a evidência do redirect → found com metadata. Isso captura avatares de perfis mesmo atrás de login-wall leve.
  - Extração de metadados mais robusta:
      - apps/web/lib/meta.ts:
      - Considera `og:image:secure_url`, `og:image`, `twitter:image`, e fallback `link[rel*=image_src]`.
      - Resolve URLs relativas com base no perfil.
  - UI:
      - O mapa lateral já exibe avatar quando status === 'found' e metadata.image existe; com essas mudanças, o Instagram deve exibir a foto de perfil.

  Por que isso ajuda

  - Instagram frequentemente redireciona para login, mas ainda serve metadados OG (título e imagem) na página pública. Agora usamos esses metadados para confirmar e extrair a foto.
  - Se conseguirmos metadata.image, mostramos imediatamente o avatar e isso sinaliza “Encontrado” com 100% de confiança visual.
      - Mantém a detecção do redirect com username como evidência forte.
      - Faz o fetch do HTML para tentar extrair og:image/título e, se conseguir, marca “Encontrado” com avatar (melhor).
      - Se não encontrar metadados suficientes, usa o redirect como fallback e classifica “Encontrado” mesmo assim (evita regressão).
      - Também amplia a extração para og:image:secure_url e link[rel*=image_src].

  O que esperar agora

  - Para perfis como “robertsonreis”:
      - Continua “Encontrado”.
      - Se a página pública trouxer og:image e título com @username, você verá a foto; caso contrário, ainda classifica como encontrado pela evidência do redirect.

- Metadata fallback específico do Instagram:
      - apps/web/lib/meta.ts:
      - Se não encontrar og:image/twitter:image/link image_src, e a URL base for instagram.com, varre todas as tags <img> em busca de alt que indiquem “foto de perfil” (palavras‑chave “profile|perfil|profil”, cobrindo PT/EN/FR/ES).
      - Extrai o src (ou o primeiro URL do srcset) e resolve relativo ao perfil.
  - Teste cobrindo o fallback:
      - apps/web/tests/meta.spec.ts: adiciona caso com  e valida que a imagem é resolvida.

  Impacto

  - Para perfis Instagram (abertos ou privados) que exibem o  no HTML, agora o engine captura a foto e a UI mostra o avatar.
  - A classificação continua “Encontrado” com maior confiança quando:
      - canonical/og:url batem, ou
      - há og:image + título com @username, ou
      - há a evidência de redirect + imagem extraída.
      - Adicionei fallback para JSON embutido: captura "profile_pic_url_hd" ou "profile_pic_url" em qualquer , decodifica escapes (\u0026, \/) e resolve a URL.
      - Mantive os outros fallbacks: og:image:secure_url → og:image → twitter:image → link rel=image_src → .
  - apps/web/tests/meta.spec.ts
      - Novo teste que valida extração via script com "profile_pic_url_hd" (com escapes), garantindo que a URL sai decodificada.
      - Parsers no HTML:
      - og:image/og:image:secure_url/twitter:image/link rel=image_src.
      - JSON embutido: profile_pic_url_hd/profile_pic_url (decodifica \u0026 e \/).
      - Busca por <img alt="...perfil..."> com variação de idiomas (profile|perfil|profil) e src/srcset.
  - Fallback final (público) para JSON da web:
      - Consulta best-effort a https://www.instagram.com/api/v1/users/web_profile_info/?username={username} com timeout curto (<= 2.5s).
      - Se vier profile_pic_url_hd/profile_pic_url, anexa em metadata.image e marca found.
  - Fluxo de decisão (Instagram):
      - canonical/og:url + username → found com metadata (preferido).
      - og:image + título com @username OU sinal de redirect → found com metadata.
      - web_profile_info com foto → found com metadata.
      - Se nada disso, ainda usa o redirect como found para evitar regressão.
      - apps/web/lib/engine.ts: se metadata.image existir e a URL hospedar em domínios conhecidos do Instagram (*.fbcdn.net, *.cdninstagram.com, *.instagram.*), passa a classificar como found mesmo que o título não contenha o @username.
  - Mantidas as outras heurísticas:
      - Redirect para login com username → found (fallback).
      - og:url/canonical válidos → found.
      - JSON embutido (profile_pic_url_hd|profile_pic_url) → found com avatar.
      -  → found com avatar.
      - Endpoint público web_profile_info (timeout curto) → found com avatar, se retornar.
…d. Agora ele só ajuda se houver outra evidência forte.

  - Fortaleci a confirmação por imagem:
      - Só aceita metadata.image para found se:
      - título contém o @username ou username, OU
      - o JSON embutido na página traz "username" igual ao perfil e inclui profile_pic_url(_hd).
  - Não usa mais “host da imagem” como critério — era amplo demais.
  - Fallback JSON público do Instagram:
      - Consulta best‑effort a web_profile_info e confirma somente se o JSON retornar user com username exato. Se o JSON retornar user = null, marcamos not_found.
  - Evitei regressões: sem “igEarlyEvidence” (redirect) como found sozinho.
      - Mantive as confirmações fortes:
      - canonical/og:url + username → found.
      - metadata.image + título com username OU JSON embutido contendo username → found.
      - API pública web_profile_info com username igual → found (ou not_found se retornar user=null).
  - Reativei um fallback não regressivo:
      - Se houver redirecionamento para login que preserva o username (igEarlyEvidence) e nenhum dos sinais acima estiver disponível, agora retorna found novamente. Isso evita que perfis reais caiam para inconclusivo.
      - Removi o fallback que marcava found somente por redirecionamento para login.
      - Confirma found com foto apenas quando:
      - Título contém o username, ou
      - O HTML embutido traz "username" igual ao perfil e temos profile_pic_url(_hd).
  - web_profile_info:
      - found somente se user.username bate com o procurado; se user=null → not_found.
  - Parser de metadados:
      - apps/web/lib/meta.ts:
      - Para Instagram, só aceita a imagem via JSON embutido se “username” no HTML bater com o do perfil.
      - Para fallback via <img alt="Foto do perfil ...">, agora exige que o alt contenha o username, além de palavras‑chave “profile|perfil|profil”.
… verdadeiros:

      - canonical ou og:url batem com o perfil.
      - username aparece no HTML (texto/título) ou no parsing anterior (usernameOk).
      - JSON embutido contém "username" exatamente igual ao procurado.
      - Há imagem de avatar (metadata.image) hospedada em domínios do Instagram (fbcdn.net/cdninstagram.com/instagram).
  - Mantém fallback via web_profile_info:
      - found apenas se retornar user.username igual ao procurado (e leva a foto).
      - not_found se user === null.

  Removi novamente a confirmação baseada só no redirecionamento para login.
      - apps/web/lib/meta.ts: além de og/meta/link, agora percorre todos os  e tenta parsear JSON grande (ProfilePage/graphql). Busca recursivamente por user.username e profile_pic_url(_hd); aceita a imagem somente se username do JSON
  bate com o solicitado. Mantém os fallbacks existentes (JSON plano com username, e ).
  - Padrões de sucesso do Instagram mais estritos:
      - apps/web/lib/sites.core.ts: successPatterns do IG agora exigem explicitamente a URL do perfil com {username} em rel="canonical" ou em property="og:url". Isso reduz matches genéricos.

  O engine segue com a regra 2 sinais (canonical/og:url, username no HTML, username no JSON, imagem em domínios IG) + fallback web_profile_info só quando retorna o username correto.
      - apps/web/lib/sites.core.ts: os padrões de canonical/og:url agora aceitam “instagram.com/...{username}...” em qualquer posição do path (antes estavam rígidos demais e podiam falhar).
  - Regra 2 sinais com redirect como apoio:
      - apps/web/lib/engine.ts (Instagram):
      - Calcula sinais: canonical/og:url; username no HTML/título; username no JSON da página; imagem IG (fbcdn.net/cdninstagram.com/instagram); redirect login com username.
      - Confirma found se:
        - canonical/og:url + (username HTML ou username JSON), ou
        - imagem IG + (username HTML ou username JSON), ou
        - redirect + (canonical/og:url ou username JSON ou imagem IG).
      - Evidências acumuladas (canonical, og:url, username-text, profile_image, final_url quando houve redirect).
…sem CORS.

  - Fortalecer IG com um verificador dedicado no backend:
      - GET página do perfil com UA fixo e Accept-Language en-US.
      - Extrair sinais: canonical/og:url contendo username; JSON embutido (graphql/ProfilePage) com user.username == solicitado; avatar em fbcdn.net/cdninstagram.com; título com @username.
      - Regra de confirmação: 2 sinais coerentes (ex.: og:url + username JSON; ou avatar IG + username no título/JSON).
      - Negativo robusto: página contém “Sorry, this page isn’t available” e variantes (PT/EN/ES), ou web_profile_info user=null.
  - Se quiser um “plano B” similar ao inflact: criar um endpoint próprio “/api/ig-verify?username=…” que retorna só {found, image?, title?}, isolando a lógica/headers/cookies sem poluir o motor geral. A UI usa esse endpoint, mas
  continua tudo no servidor (sem CORS).
      - apps/web/lib/engine.ts:
      - Para Instagram, primeiro chama: https://www.instagram.com/web/search/topsearch/?query={username}
      - Se no JSON houver um usuário com username exatamente igual ao procurado:
        - Retorna “found” com metadata:
          - image: profile_pic_url_hd ou profile_pic_url
          - title: full_name
        - Evidência: pattern “api: topsearch”
      - Se a lista de users vier vazia:
        - Retorna “not_found”.
      - Se não bater exato mas vier sugestões, continua com as heurísticas anteriores (canonical/og, JSON embutido, etc.).
  - Mantidas as heurísticas e fallbacks já existentes (redirect/login, og/url, JSON embutido, web_profile_info).
      - Confirma “found” somente se:
      - canonical/og/url batem com o username, E
      - há avatar com host avatars.githubusercontent.com OU o HTML contém “Followers”/“Following”.
  - Se canonical/og/url batem mas não há avatar nem “Followers/Following”, retorna “inconclusive” (evita falso positivo).
  - Se padrão de “Not Found” bater, retorna “not_found” imediatamente.
  - Racional:
      - Perfis reais sempre têm avatar (mesmo o identicon padrão hospedado em avatars.githubusercontent.com) e em geral exibem “Followers/Following”.
      - Páginas 404 do GitHub podem ter canonical com o username, mas não terão avatar em avatars.githubusercontent.com nem métricas de seguidores.
@vercel

vercel Bot commented Sep 19, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
alias-map-web Ready Ready Preview Comment Sep 19, 2025 4:27am

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@bob-reis
bob-reis merged commit 1000241 into main Sep 19, 2025
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant