Repository navigation
PAV-125: [Backend/Valkey] Implementar índices por família, cache determinístico e match score - #307
Merged
Conversation
Benevanio
approved these changes
Oct 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linear
PAV-125 — Backend/Valkey: Implementar índices por família, cache determinístico e match score
Objetivo
Implementa a infraestrutura de persistência, indexação e busca necessária para suportar de forma eficiente a taxonomia profissional introduzida nas PAV-123/PAV-124.
A implementação estabelece uma separação explícita entre:
O Processor passa a persistir a vaga no PostgreSQL antes de publicar ou atualizar seus índices no Valkey.
Fluxo principal:
Isso permite reconstruir e reconciliar os índices sem depender de uma nova coleta nas fontes externas.
Catálogo PostgreSQL
Foi criado um catálogo persistente de vagas no PostgreSQL porque não existia uma implementação equivalente reutilizável no projeto.
A tabela preserva o ID estável atual da vaga e armazena o documento necessário para reconstrução do catálogo e dos índices.
Também foram adicionados dados de ciclo de vida e revisão para permitir:
Migration adicionada:
O PostgreSQL passa a ser a fonte de verdade do catálogo.
Ciclo de vida das vagas
O ciclo atual de aproximadamente nove dias foi preservado, mas deixou de depender exclusivamente do TTL do Valkey.
Uma nova coleta da mesma vaga:
Reclassificar uma vaga não renova artificialmente sua expiração.
Vagas expiradas deixam de participar do catálogo ativo e dos índices de busca, mas não precisam ser fisicamente removidas do PostgreSQL.
O período é configurável por ambiente.
Índices Valkey
Foram implementados índices separados para os modos definidos pela PAV-124:
Compatibilidade com busca
any, contendo primary ou related.Somente vagas cuja família principal corresponde à família consultada.
Somente famílias relacionadas.
Também foi implementado registro inverso de membership por vaga, permitindo descobrir seus índices anteriores sem percorrer todas as famílias.
Apenas as 13 famílias canônicas podem ser indexadas.
otherpermanece interno e não integra os índices públicos.Reclassificação e consistência
A atualização dos índices foi projetada para suportar reclassificações como:
ou alterações simultâneas de família principal e famílias relacionadas.
A publicação usa operação Lua no Valkey para:
A persistência PostgreSQL acontece antes da indexação.
Se o commit no PostgreSQL falhar, a vaga não é publicada nos novos índices.
Busca por famílias
A busca da PAV-124 passa a utilizar os índices da PAV-125 quando o novo namespace está ativo.
São suportados:
familyMode=any;familyMode=primary;Para múltiplas famílias, o conjunto de candidatos é resolvido no Valkey antes da paginação.
Os filtros residuais são aplicados antes do cálculo final de:
total;Não há pós-filtro depois da paginação.
Foi mantido fallback compatível com o mecanismo anterior enquanto o novo índice ainda não estiver ativo.
Cache determinístico de busca
Foi criada uma camada de cache específica para
/jobs/search.A chave considera os parâmetros que afetam o resultado, incluindo:
familyMode;As famílias são:
Portanto, por exemplo:
e:
produzem o mesmo fingerprint.
familyMode=primaryefamilyMode=anyproduzem fingerprints diferentes.Texto livre não é exposto diretamente na chave: é representado por fingerprint.
O cache possui TTL e geração para invalidação.
Invalidação
A geração de busca é avançada somente depois de uma atualização de catálogo/indexação bem-sucedida.
Não foi introduzido:
KEYS jobs:search:*;FLUSHALL;FLUSHDB;A limpeza administrativa existente também foi protegida para não remover o namespace ativo do catálogo.
Rebuild dos índices
Foi criado processo explícito de rebuild a partir do PostgreSQL.
Fluxo:
O rebuild:
KEYS;FLUSHALLouFLUSHDB;Reconciliação
Foi adicionada reconciliação entre:
Ela detecta situações como:
anyincorreto;O comportamento padrão é read-only.
Correções exigem execução explícita.
Backfill
Como o catálogo anterior existia somente no Valkey, foi implementado fluxo controlado para migração inicial.
O backfill:
KEYS;A ativação do novo Processor exige que migration e backfill/rebuild sejam concluídos previamente.
CLI de manutenção
Foi adicionada CLI específica do catálogo em:
Ela concentra as operações de manutenção do catálogo, rebuild e reconciliação sem misturá-las ao fluxo normal do Processor.
Match score — Produto e Product Design
O match foi adaptado especificamente para:
product;product_design.Para Produto são consideradas evidências relacionadas a:
Para Product Design são consideradas evidências relacionadas a:
HTML/CSS podem contribuir para Product Design, mas não determinam o score principal.
Ausência de linguagens/frameworks não reduz o score de Product/Product Design.
As demais famílias continuam utilizando a fórmula anterior.
Também foi adicionado
matchReasonsopcional com justificativas públicas do match, sem expor pesos internos, PII ou descrição completa da vaga.Preferências de usuário
Foi revisada a semântica do modelo existente de
UserPreferences.No contrato atual:
jobTypesrepresentaRemoto,HíbridoePresencial;remoteOnlyrepresenta preferência por remoto;searchLocationrepresenta localização de busca;keywordscontém texto livre.Por isso:
jobTypespermanece utilizado como modalidade;keywordsnão é usado para inferir família profissional;contractnão é inferido porque não existe atualmente fonte segura no modelo;familytambém não é inferida a partir de texto livre.Nenhum contrato público de preferências foi alterado.
Compatibilidade
Foram preservados os contratos introduzidos pela PAV-124:
family;familyMode;any;/jobs/filters/options.Também foram preservados:
Não há alterações em:
frontend/**;front_admin/**;package-lock.json.Principais arquivos
PostgreSQL
Processor
Backend / busca
Match
Documentação
Testes e validações
Validações executadas durante a implementação:
go test -raceaprovado;go vetaprovado;git diff --checkaprovado.Também foram executados testes de integração com PostgreSQL e Redis/Valkey isolados.
Os testes cobrem, entre outros:
Após a revisão final das preferências, 123 testes direcionados adicionais passaram, junto com typecheck e
git diff --check.Performance
A arquitetura reduz a quantidade de documentos hidratados durante buscas indexadas e evita consultas por vaga.
A busca opera em batches e mantém o PostgreSQL fora do caminho crítico normal de leitura.
Entretanto, o requisito:
não foi comprovado em ambiente representativo de produção.
Não foi criado benchmark artificial para declarar essa meta como atendida.
Essa medição deve ser realizada em staging/ambiente representativo.
Deploy / migração
Esta alteração não deve ser ativada simplesmente iniciando o novo Processor.
Ordem esperada:
O PostgreSQL é a fonte de verdade.
O Valkey pode ser reconstruído a partir dele.
Rollback
Em caso de problema durante a ativação:
A presença do catálogo PostgreSQL permite reconstruir os índices sem nova coleta externa.
Fora do escopo
Não fazem parte desta task:
frontend/**;front_admin/**;package-lock;Checklist
primaryrelatedanyKEYS,FLUSHALLouFLUSHDBgit diff --check