Leads Extractor
Extrator assíncrono de canais de podcast, entrevistados e contatos públicos. O backend usa Rust, Actix, Tokio, Chromiumoxide, PostgreSQL e OpenRouter; 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 LOCKEDe executam os pipelines com concorrência configurável. - Cada navegação de documento e busca segue
perfil limpo -> aquecer a mesma origem -> acessarno 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
PATHpara execução fora do container
Desenvolvimento local
-
Inicie somente o PostgreSQL. O usuário, banco e senha
leadssão defaults exclusivamente locais:docker compose up -d postgresSe a porta
5432estiver ocupada:POSTGRES_PORT=55432 docker compose up -d postgresNesse caso, ajuste também a porta em
backend/.env. -
Prepare o backend:
Crie
backend/.envcom as variáveis descritas na seção Variáveis de ambiente abaixo.Edite apenas a cópia local
backend/.env. Além do OpenRouter 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; usetruesob HTTPS.AUTH_COOKIE_SAME_SITE=strict: default recomendado;laxtambém é suportado, mas nenhum dos modos habilita autenticação cross-site.
Em seguida, inicie a API manualmente:
cd backend cargo runO backend cria
schema_migrationse aplica as migrations pendentes no startup. O PostgreSQL não executa SQL viadocker-entrypoint-initdb.d.SERVER_PORTé configurável e usa8080por padrão. -
Em outro terminal, prepare o frontend:
cd frontend npm ciCrie
frontend/.envcom as variáveis descritas na seção Variáveis de ambiente abaixo, então:npm run devSe a porta
8080estiver ocupada, escolha outra emSERVER_PORTnobackend/.enve defina a mesma porta emVITE_API_URLnofrontend/.envantes de iniciar os dois processos. -
Abra
http://localhost:5173e autentique-se com as credenciais definidas nobackend/.env. Por padrão, a API local fica emhttp://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 OpenRouter 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
Referência completa das variáveis: backend/src/config.rs e o .env na raiz
(usado pelo Compose).
OPENROUTER_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.OPENROUTER_PRIMARY_MODEL/OPENROUTER_FALLBACK_MODEL,OPENROUTER_BASE_URL, timeouts e retries: configuração do provedor de IA (OpenRouter). Se o modelo principal estiver indisponível ou falhar, o próprio OpenRouter tenta automaticamente o modelo de fallback na mesma requisição; deixeOPENROUTER_FALLBACK_MODELvazio para desativar o fallback.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; default43200segundos.AUTH_COOKIE_SECURE:falseapenas durante desenvolvimento HTTP local etruequando a aplicação estiver sob HTTPS.AUTH_COOKIE_SAME_SITE:strictpor padrão oulax; ambos exigem frontend e API same-site.SERVER_HOSTeSERVER_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: 2500–15000 ms).BROWSER_MACRO_PAUSE_*: faixa de sessões e duração das pausas maiores; padrões de 15–20 sessões e 30–90 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_USERNAMEeDATAIMPULSE_PROXY_PASSWORD: obrigatórias quando o proxy estiver ativo.DATAIMPULSE_PROXY_HOST, porta e país: parâmetros da DataImpulse. O login efetivo nunca incluisessid, portanto cada requisição usa o pool rotativo.MAX_INTERVIEWEES_PER_RUN: teto operacional por execução, aplicado também sob concorrência.0processa todos; para o teste externo controlado use100(valor já usado no.envlocal 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: mantenhafalselocalmente; 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
Referência completa das variáveis: .env na raiz (usado pelo Compose).
VITE_API_URL: URL da API; localmente,http://localhost:8080. Deve usar o mesmoSERVER_PORTconfigurado no backend.VITE_API_POLL_INTERVAL: intervalo de atualização do painel, em milissegundos.VITE_DEMO_MODE: mantenhafalsepara autenticação e dados reais.trueativa 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.