2026-07-26 21:17:57 -03:00
2026-07-26 21:17:57 -03:00
2026-07-26 21:17:57 -03:00
2026-07-26 21:17:57 -03:00
2026-07-26 21:17:57 -03:00
2026-07-26 21:17:57 -03:00
2026-07-26 21:17:57 -03:00
2026-07-26 21:17:57 -03:00

Leads Extractor

Extrator assíncrono de canais de podcast, entrevistados e contatos públicos. O backend usa Rust, Actix, Tokio, Chromiumoxide, PostgreSQL e OpenAI; o frontend usa SvelteKit, TypeScript e Tailwind CSS.

Arquitetura

  • A API Actix responde rápido e grava execuções na fila PostgreSQL.
  • Workers Tokio reclamam jobs com FOR UPDATE SKIP LOCKED e executam os pipelines com concorrência configurável.
  • Cada navegação de documento e busca segue perfil limpo -> aquecer a mesma origem -> acessar no Chromium headless. Assim, TLS, HTTP/2, Client Hints, cookies e carregamento de assets são produzidos pelo navegador real; a sessão e o processo são descartados ao fim. Downloads binários continuam em um cliente HTTP isolado, sem reaproveitar conexões.
  • A IA recebe DTOs preparados pelo backend e nunca possui acesso ao banco.
  • Contatos são normalizados e deduplicados, preservando todas as origens e evidências.
  • O Docker Compose local executa somente o PostgreSQL; API e interface rodam manualmente, facilitando logs, recompilação e depuração.

Requisitos locais

  • Docker com Compose
  • Rust 1.96 ou compatível com edition 2024
  • Node.js 24+ e npm
  • Google Chrome/Chromium disponível no PATH para execução fora do container

Desenvolvimento local

  1. Inicie somente o PostgreSQL. O usuário, banco e senha leads são defaults exclusivamente locais:

    docker compose up -d postgres
    

    Se a porta 5432 estiver ocupada:

    POSTGRES_PORT=55432 docker compose up -d postgres
    

    Nesse caso, ajuste também a porta em backend/.env.

  2. Prepare o backend:

    cp backend/.env.example backend/.env
    

    Edite apenas a cópia local backend/.env. Além da OpenAI e da DataImpulse, defina um usuário de acesso e uma senha exclusiva com pelo menos 12 caracteres:

    • AUTH_USERNAME: obrigatório; não possui default seguro.
    • AUTH_PASSWORD: obrigatória; mínimo de 12 caracteres.
    • AUTH_SESSION_TTL_SECS=43200: duração padrão da sessão, em segundos.
    • AUTH_COOKIE_SECURE=false: somente para HTTP local; use true sob HTTPS.
    • AUTH_COOKIE_SAME_SITE=strict: default recomendado; lax também é suportado, mas nenhum dos modos habilita autenticação cross-site.

    Em seguida, inicie a API manualmente:

    cd backend
    cargo run
    

    O backend cria schema_migrations e aplica as migrations pendentes no startup. O PostgreSQL não executa SQL via docker-entrypoint-initdb.d. SERVER_PORT é configurável e usa 8080 por padrão.

  3. Em outro terminal, prepare o frontend:

    cd frontend
    npm ci
    cp .env.example .env
    npm run dev
    

    Se a porta 8080 estiver ocupada, escolha outra em SERVER_PORT no backend/.env e defina a mesma porta em VITE_API_URL no frontend/.env antes de iniciar os dois processos.

  4. Abra http://localhost:5173 e autentique-se com as credenciais definidas no backend/.env. Por padrão, a API local fica em http://localhost:8080.

Operação local

O Compose não constrói nem inicia backend ou frontend. Ele gerencia somente o PostgreSQL 18 pela imagem postgres:18:

docker compose config --quiet
docker compose up -d postgres
docker compose ps postgres

Execute cargo run em backend/ e npm run dev em frontend/, em terminais separados. Os endpoints locais são:

  • Frontend: http://localhost:5173
  • Backend: http://localhost:8080
  • Healthcheck: http://localhost:8080/api/health

Para acompanhar ou encerrar apenas o banco:

docker compose logs -f postgres
docker compose down

docker compose down mantém o volume PostgreSQL. docker compose down -v remove o banco e causa perda de dados; use apenas quando isso for intencional.

Publicação

O Compose fornecido é destinado ao banco local. Em publicação, execute backend e frontend com o gerenciador de processos ou orquestrador escolhido e mantenha senhas, chave da OpenAI e credenciais da DataImpulse em um gerenciador de segredos. Defina uma senha PostgreSQL forte, FRONTEND_ORIGIN com a origem HTTPS exata e AUTH_COOKIE_SECURE=true. Não publique a API sem TLS.

A sessão de autenticação usa cookie HttpOnly, enviado pelo frontend com credenciais incluídas, e política SameSite restritiva. O frontend usa POST /api/auth/login, GET /api/auth/session e POST /api/auth/logout.

Frontend e API precisam permanecer same-site, inclusive quanto ao esquema HTTP/HTTPS. CORS não torna cookies SameSite=Strict ou Lax utilizáveis entre sites diferentes, portanto implantação cross-site não é suportada. Em desenvolvimento, use o mesmo hostname nas duas URLs — por exemplo, não misture localhost e 127.0.0.1. Se forem origens diferentes dentro do mesmo site, configure FRONTEND_ORIGIN com a origem exata do frontend.

O cliente adiciona automaticamente X-CSRF-Protection: 1 a toda requisição mutante, envia o cookie com credentials: include e o navegador fornece Origin. Clientes manuais precisam enviar o mesmo cabeçalho e a origem esperada. O login possui rate limit; excesso de tentativas recebe HTTP 429. Respostas privadas usam Cache-Control: no-store para evitar retenção por caches do navegador ou de intermediários.

As sessões atuais vivem somente na memória do processo backend. Execute uma única instância: reiniciar ou substituir o processo encerra todas as sessões e exige novo login. Antes de usar múltiplas réplicas, mova o armazenamento de sessões para um serviço compartilhado, como PostgreSQL ou Redis.

Variáveis de ambiente

Compose

Variável Default local Quando alterar
POSTGRES_DB leads_extractor Nome do banco
POSTGRES_USER leads Usuário do banco
POSTGRES_PASSWORD leads Obrigatória fora do ambiente local
POSTGRES_PORT 5432 Porta publicada no host

Se alterar usuário, senha, banco ou porta do Compose, atualize também DATABASE_URL em backend/.env. Senhas com caracteres reservados precisam estar percent-encoded nessa URL.

Backend

O arquivo de referência é backend/.env.example.

  • OPENAI_API_KEY: obrigatória para resumos, categorização e extração por IA; o servidor pode iniciar sem ela, mas esses fluxos falham de forma explícita.
  • OPENAI_MODEL, OPENAI_BASE_URL, timeouts e retries: configuração do provedor de IA.
  • AUTH_USERNAME: usuário obrigatório para acessar a aplicação; não há valor padrão seguro.
  • AUTH_PASSWORD: senha obrigatória com pelo menos 12 caracteres.
  • AUTH_SESSION_TTL_SECS: validade da sessão; default 43200 segundos.
  • AUTH_COOKIE_SECURE: false apenas durante desenvolvimento HTTP local e true quando a aplicação estiver sob HTTPS.
  • AUTH_COOKIE_SAME_SITE: strict por padrão ou lax; ambos exigem frontend e API same-site.
  • SERVER_HOST e SERVER_PORT: endereço da API; a porta padrão é 8080.
  • BROWSER_MIN_NAVIGATION_DELAY_MS / BROWSER_MAX_NAVIGATION_DELAY_MS: intervalo aleatório aplicado antes de cada sessão de navegador (padrão: 250015000 ms).
  • BROWSER_MACRO_PAUSE_*: faixa de sessões e duração das pausas maiores; padrões de 1520 sessões e 3090 segundos.
  • FRONTEND_ORIGIN: origem exata autorizada pelo CORS e pela validação das requisições mutantes.
  • DATAIMPULSE_PROXY_ENABLED: fica ativo por padrão; desative somente para diagnóstico local explícito.
  • DATAIMPULSE_PROXY_USERNAME e DATAIMPULSE_PROXY_PASSWORD: obrigatórias quando o proxy estiver ativo.
  • DATAIMPULSE_PROXY_HOST, porta e país: parâmetros da DataImpulse. O login efetivo nunca inclui sessid, portanto cada requisição usa o pool rotativo.
  • MAX_INTERVIEWEES_PER_RUN: teto operacional por execução, aplicado também sob concorrência. 0 processa todos; para o teste externo controlado use 100 (valor já usado no .env local desta instalação).
  • WORKER_CONCURRENCY, BROWSER_CONCURRENCY, limites de crawl e timeouts: orçamento operacional.
  • MEDIA_DIR: diretório local de logos, imagens e demais mídias coletadas.
  • BROWSER_NO_SANDBOX: mantenha false localmente; habilite somente em um ambiente isolado que não ofereça user namespaces.

Nunca comite backend/.env, frontend/.env, tokens, senhas, cookies ou credenciais do proxy. Os .dockerignore também excluem esses arquivos do contexto de build, mas isso não substitui um gerenciador de segredos.

Frontend

O arquivo de referência é frontend/.env.example.

  • VITE_API_URL: URL da API; localmente, http://localhost:8080. Deve usar o mesmo SERVER_PORT configurado no backend.
  • VITE_API_POLL_INTERVAL: intervalo de atualização do painel, em milissegundos.
  • VITE_DEMO_MODE: mantenha false para autenticação e dados reais. true ativa somente a demonstração local explícita.

Dados persistentes

  • postgres_data: cluster PostgreSQL 18 gerenciado pelo Compose.
  • MEDIA_DIR: diretório no host usado pelo backend iniciado manualmente para logos, imagens e demais mídias coletadas.

Faça backup do volume e do diretório de mídia. Alterar ou adicionar migrations não recria o banco: o backend registra cada versão aplicada em schema_migrations.

Fluxos

  • Busca: procura canais de podcast e permite revisar a lista.
  • Entrevistados: coleta vídeos, metadados e legendas; a IA identifica todos os convidados e resolve duplicidades. A ordem é português/original preferido e depois qualquer faixa original disponível, sem tradução artificial. Transcrições longas são processadas em trechos sobrepostos.
  • Contatos: pesquisa o nome/contexto no Google e percorre páginas em BFS até cinco níveis, classificando cada contato como pessoal ou comercial. Links adicionais escolhidos pela IA só são visitados quando possuem evidência na página e entram novamente no mesmo ciclo agentivo até o quinto nível.

Falhas externas passam pelos retries com backoff, jitter, sessão/IP novo e timeout de cada módulo. Se um item ainda falhar, o job é repetido e reaproveita vídeos já concluídos como checkpoints. Falta de créditos pausa o mesmo job sem perder a possibilidade de retomada pelo botão de retry. A resolução de identidades possui um limite global de concorrência para reservar conexões do pool PostgreSQL mesmo com várias execuções simultâneas.

Verificações

docker compose config --quiet
docker compose up -d postgres

cd backend
cargo fmt --all -- --check
cargo check --all-targets
cargo test --all-targets
cargo clippy --all-targets -- -D warnings

cd ../frontend
npm ci
npm run check
npm run build

O crawler aceita apenas URLs HTTP/HTTPS públicas e bloqueia destinos locais ou privados. Não há automação de login, CAPTCHA ou áreas protegidas.

S
Description
No description provided
Readme
649 KiB
Languages
Rust 76.9%
Svelte 10.2%
CSS 6.2%
TypeScript 4%
PLpgSQL 2.4%
Other 0.2%