Repository navigation
Conversation
…as na API (#289) ## Linear [PAV-124 — [Backend] Implementar filtros avançados e contrato de famílias na API](https://linear.app/candidateappbr/issue/PAV-124) ## Objetivo Implementar no backend um contrato completo e documentado para filtros por família profissional, utilizando a taxonomia canônica consolidada na PAV-123. A entrega adiciona: - suporte a uma ou várias famílias; - suporte a múltiplas famílias por vírgula; - suporte à repetição do parâmetro `family`; - parâmetro `familyMode=primary|any`; - `familyMode=any` como padrão; - operação `OR` entre famílias; - operação `AND` entre famílias e os demais filtros; - validação e normalização centralizadas; - endpoint `/jobs/filters/options`; - respostas de erro estáveis; - documentação OpenAPI/Swagger; - testes unitários, de contrato e integração. ## Resumo das alterações Foi criado um fluxo centralizado para interpretação dos filtros por família. A API agora aceita: GET /jobs/search?family=backend GET /jobs/search?family=backend,fullstack GET /jobs/search?family=backend&family=fullstack Os formatos múltiplos são normalizados para uma estrutura determinística e equivalente. Também foi adicionado: familyMode=primary|any Comportamento padrão: familyMode=any ## Taxonomia A implementação reutiliza a taxonomia canônica criada na PAV-123. Famílias públicas válidas: - `backend` - `frontend` - `fullstack` - `mobile` - `data` - `devops` - `platform` - `qa` - `security` - `product` - `product_design` - `software` - `leadership` O valor: other continua sendo interno e não pode ser utilizado como filtro público. Labels como: Backend Full Stack Dados e IA Design de Produto também não são aceitos como identificadores. ## `familyMode` Foram adicionados dois modos de busca: ### `any` Considera: classification.primaryFamily classification.relatedFamilies A vaga corresponde quando qualquer família solicitada estiver como principal ou relacionada. ### `primary` Considera somente: classification.primaryFamily Uma vaga cuja família esteja apenas em `relatedFamilies` não corresponde nesse modo. ## Múltiplas famílias Famílias múltiplas utilizam operação lógica `OR`. Exemplo: family=backend,fullstack&familyMode=primary Semântica: primaryFamily = backend OR primaryFamily = fullstack Com `familyMode=any`, cada família pode corresponder à principal ou às relacionadas. ## Combinação com outros filtros O grupo de famílias utiliza `AND` em relação aos demais filtros existentes. Exemplo: family=backend,fullstack familyMode=any seniority=senior modality=remote Semântica: (backend OR fullstack) AND senior AND remote Foram preservados os filtros existentes de: - senioridade; - modalidade; - localização; - contrato; - texto; - provider; - tecnologias; - paginação; - ordenação; - demais filtros já suportados. ## Parser centralizado Foi adicionado um parser específico para `family` e `familyMode`. O parser: - aceita string única; - aceita lista separada por vírgula; - aceita parâmetro repetido; - combina os formatos; - remove espaços; - remove valores vazios; - remove duplicidades; - valida contra a taxonomia canônica; - aplica ordenação determinística; - aplica `familyMode=any` como padrão; - retorna estrutura tipada. Estrutura normalizada: { families: JobFamily[]; familyMode: "primary" | "any"; } ## Ordem determinística A ordem enviada pelo cliente não altera o resultado normalizado. Exemplos equivalentes: ?family=backend,fullstack ?family=fullstack,backend ?family=backend&family=fullstack Todos resultam na mesma estrutura normalizada. ## Full Stack `fullstack` continua sendo uma família própria. A busca: ?family=fullstack&familyMode=primary não é transformada automaticamente em: backend OR frontend Para consultar as três famílias, o cliente deve enviar explicitamente: ?family=backend,frontend,fullstack ## DevOps e Platform `devops` e `platform` permanecem famílias independentes. A busca: ?family=devops&familyMode=primary não inclui automaticamente vagas primárias de `platform`. Para consultar ambas: ?family=devops,platform ## Validação e erros Famílias inválidas retornam: 400 Bad Request Código: INVALID_JOB_FAMILY Valores inválidos não são: - ignorados; - convertidos para `other`; - parcialmente aceitos; - tratados com fallback silencioso. `familyMode` inválido também retorna: 400 Bad Request Código: INVALID_FAMILY_MODE O envelope de erro existente no backend foi preservado. ## Camada de consulta Foi criada uma camada de repository dedicada para aplicar corretamente a semântica de famílias antes da paginação final. A implementação garante que: - página e total utilizem o mesmo conjunto de filtros; - não exista pós-filtro incorreto somente na página retornada; - o total reflita os mesmos critérios de busca; - o controller não contenha regra de negócio; - o service não reinterprete valores já normalizados; - a camada de consulta receba a semântica explícita. Até a implementação dos novos índices da próxima PAV, a busca utiliza uma estratégia funcionalmente correta baseada na persistência atual. ## Limitação temporária Nesta entrega, a busca por famílias ainda possui custo linear em relação aos candidatos avaliados. Essa decisão é temporária e deliberada. A otimização ficará para a próxima sub-issue de Valkey, responsável por: - novos índices por família; - cache determinístico; - invalidação; - otimização de match score. Também permanece a limitação de não existir snapshot transacional entre múltiplas leituras do Valkey. Esses pontos não alteram a correção funcional do contrato implementado nesta PAV. ## Endpoint de opções Foi adicionado: GET /jobs/filters/options O endpoint retorna a taxonomia oficial para consumo dos clientes. A resposta inclui: taxonomyVersion families familyModes Os modos expostos são: any primary Com `any` marcado como padrão. O endpoint: - utiliza a taxonomia canônica; - não inclui `other`; - possui ordem determinística; - não consulta todas as vagas; - não executa contagens pesadas; - não depende do Jobs Processor em execução; - permite cache HTTP; - possui ETag associado à taxonomia. ## Cache HTTP O endpoint de opções utiliza headers de cache HTTP. A estratégia permite reutilização do contrato estático sem consultas desnecessárias ao backend. ## OpenAPI / Swagger A documentação foi atualizada para incluir: - parâmetro `family`; - múltiplos valores; - formato separado por vírgula; - parâmetro repetido; - `familyMode`; - valor padrão `any`; - operação `OR`; - combinação `AND`; - famílias válidas; - comportamento de Full Stack; - diferença entre DevOps e Platform; - respostas `400`; - endpoint `/jobs/filters/options`; - exemplos de requisição e resposta. O arquivo do Swagger também foi reformatado para melhorar legibilidade, sem alteração funcional correspondente a todo o volume exibido no diff. ## Compatibilidade O contrato antigo continua válido: GET /jobs/search?family=backend O comportamento padrão `any` preserva a semântica anterior observada no backend, que já considerava famílias principais e relacionadas. Também foram preservados: - formato geral da resposta; - paginação; - filtros existentes; - autenticação; - rate limit; - campos atuais; - nomes das famílias. ## Arquivos e módulos alterados ### Backend Principais arquivos: backend/src/lib/errors.ts backend/src/modules/jobs/controllers/jobFilterOptions.controller.ts backend/src/modules/jobs/controllers/searchJobs.controller.ts backend/src/modules/jobs/filters/jobSearch.filter.ts backend/src/modules/jobs/parsers/familyQuery.parser.ts backend/src/modules/jobs/parsers/jobSearchQuery.parser.ts backend/src/modules/jobs/repositories/jobSearch.repository.ts backend/src/modules/jobs/services/searchJobs.service.ts backend/src/modules/jobs/types/jobSearch.types.ts backend/src/routes/jobs.routes.ts backend/src/swagger.ts ### Testes Foram adicionados e atualizados testes em: backend/tests/integration/routes/searchJobs.routes.test.ts backend/tests/unit/app.test.ts backend/tests/unit/modules/jobs/familyQuery.parser.test.ts backend/tests/unit/modules/jobs/jobSearch.filter.test.ts backend/tests/unit/modules/jobs/jobSearch.repository.test.ts backend/tests/unit/modules/jobs/searchJobs.service.test.ts backend/tests/unit/swagger.test.ts ### Documentação Atualizado: BACKEND.md ### Git O `.gitignore` foi atualizado para ignorar o relatório local: PAV-124_REPORT.md ## Fora do escopo Esta alteração não inclui: - novos índices principais e relacionados no Valkey; - reconstrução completa dos índices; - cache keys finais; - invalidação de cache por reclassificação; - alterações no match score; - métricas Prometheus completas; - dashboard administrativo; - alterações em `frontend/**`; - alterações em `front_admin/**`; - alterações no Jobs Processor; - alterações no `package-lock.json`; - mudanças de comunicação Node ↔ Go; - introdução de gRPC. ## Validação realizada Foram executados: npm test -- --run tests/unit tests/integration Resultado: 756 testes aprovados 73 arquivos de teste Também passaram: TypeScript typecheck validação da estrutura OpenAPI git diff --check O lint não cobre atualmente o backend pela configuração existente do projeto. ## Segurança e desempenho A implementação: - valida os parâmetros antes da consulta; - preserva autenticação; - preserva rate limiting; - evita interpolação insegura de parâmetros; - não introduz regex controlada pelo usuário; - não carrega todas as vagas retornadas em memória para depois paginar; - mantém página e total consistentes. ## Riscos O principal risco atual é de desempenho em bases maiores, devido ao custo linear temporário da estratégia utilizada antes da criação dos novos índices de família no Valkey. Esse risco já está isolado para a próxima PAV de otimização. Não foi introduzida alteração destrutiva de dados. ## Rollback O rollback pode ser feito revertendo os commits desta PR. Não existem migrações destrutivas associadas a esta entrega. ## Checklist - [x] Suporte a uma família - [x] Suporte a múltiplas famílias - [x] Formato por vírgula - [x] Parâmetro repetido - [x] Parser centralizado - [x] Remoção de duplicidades - [x] Ordem determinística - [x] `familyMode=primary` - [x] `familyMode=any` - [x] `any` como modo padrão - [x] OR entre famílias - [x] AND com demais filtros - [x] Full Stack preservado como família própria - [x] DevOps e Platform independentes - [x] Família inválida retorna 400 - [x] `familyMode` inválido retorna 400 - [x] `other` não é público - [x] Página e total usam os mesmos filtros - [x] Endpoint `/jobs/filters/options` - [x] 13 famílias canônicas - [x] Cache HTTP - [x] ETag - [x] OpenAPI / Swagger atualizado - [x] Testes unitários - [x] Testes de integração - [x] 756 testes aprovados - [x] Typecheck aprovado - [x] `git diff --check` - [x] Nenhuma alteração em `frontend/**` - [x] Nenhuma alteração em `front_admin/**` - [x] Nenhuma alteração em `scraper-go/**` - [x] Nenhuma alteração em `package-lock.json`
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-124 — [Backend] Implementar filtros avançados e contrato de famílias na API
Objetivo
Implementar no backend um contrato completo e documentado para filtros por família profissional, utilizando a taxonomia canônica consolidada na PAV-123.
A entrega adiciona:
family;familyMode=primary|any;familyMode=anycomo padrão;ORentre famílias;ANDentre famílias e os demais filtros;/jobs/filters/options;Resumo das alterações
Foi criado um fluxo centralizado para interpretação dos filtros por família.
A API agora aceita:
Os formatos múltiplos são normalizados para uma estrutura determinística e equivalente.
Também foi adicionado:
Comportamento padrão:
Taxonomia
A implementação reutiliza a taxonomia canônica criada na PAV-123.
Famílias públicas válidas:
backendfrontendfullstackmobiledatadevopsplatformqasecurityproductproduct_designsoftwareleadershipO valor:
continua sendo interno e não pode ser utilizado como filtro público.
Labels como:
também não são aceitos como identificadores.
familyModeForam adicionados dois modos de busca:
anyConsidera:
A vaga corresponde quando qualquer família solicitada estiver como principal ou relacionada.
primaryConsidera somente:
Uma vaga cuja família esteja apenas em
relatedFamiliesnão corresponde nesse modo.Múltiplas famílias
Famílias múltiplas utilizam operação lógica
OR.Exemplo:
Semântica:
Com
familyMode=any, cada família pode corresponder à principal ou às relacionadas.Combinação com outros filtros
O grupo de famílias utiliza
ANDem relação aos demais filtros existentes.Exemplo:
Semântica:
Foram preservados os filtros existentes de:
Parser centralizado
Foi adicionado um parser específico para
familyefamilyMode.O parser:
familyMode=anycomo padrão;Estrutura normalizada:
Ordem determinística
A ordem enviada pelo cliente não altera o resultado normalizado.
Exemplos equivalentes:
Todos resultam na mesma estrutura normalizada.
Full Stack
fullstackcontinua sendo uma família própria.A busca:
não é transformada automaticamente em:
Para consultar as três famílias, o cliente deve enviar explicitamente:
DevOps e Platform
devopseplatformpermanecem famílias independentes.A busca:
não inclui automaticamente vagas primárias de
platform.Para consultar ambas:
Validação e erros
Famílias inválidas retornam:
Código:
Valores inválidos não são:
other;familyModeinválido também retorna:Código:
O envelope de erro existente no backend foi preservado.
Camada de consulta
Foi criada uma camada de repository dedicada para aplicar corretamente a semântica de famílias antes da paginação final.
A implementação garante que:
Até a implementação dos novos índices da próxima PAV, a busca utiliza uma estratégia funcionalmente correta baseada na persistência atual.
Limitação temporária
Nesta entrega, a busca por famílias ainda possui custo linear em relação aos candidatos avaliados.
Essa decisão é temporária e deliberada.
A otimização ficará para a próxima sub-issue de Valkey, responsável por:
Também permanece a limitação de não existir snapshot transacional entre múltiplas leituras do Valkey.
Esses pontos não alteram a correção funcional do contrato implementado nesta PAV.
Endpoint de opções
Foi adicionado:
O endpoint retorna a taxonomia oficial para consumo dos clientes.
A resposta inclui:
Os modos expostos são:
Com
anymarcado como padrão.O endpoint:
other;Cache HTTP
O endpoint de opções utiliza headers de cache HTTP.
A estratégia permite reutilização do contrato estático sem consultas desnecessárias ao backend.
OpenAPI / Swagger
A documentação foi atualizada para incluir:
family;familyMode;any;OR;AND;400;/jobs/filters/options;O arquivo do Swagger também foi reformatado para melhorar legibilidade, sem alteração funcional correspondente a todo o volume exibido no diff.
Compatibilidade
O contrato antigo continua válido:
O comportamento padrão
anypreserva a semântica anterior observada no backend, que já considerava famílias principais e relacionadas.Também foram preservados:
Arquivos e módulos alterados
Backend
Principais arquivos:
Testes
Foram adicionados e atualizados testes em:
Documentação
Atualizado:
Git
O
.gitignorefoi atualizado para ignorar o relatório local:Fora do escopo
Esta alteração não inclui:
frontend/**;front_admin/**;package-lock.json;Validação realizada
Foram executados:
Resultado:
Também passaram:
O lint não cobre atualmente o backend pela configuração existente do projeto.
Segurança e desempenho
A implementação:
Riscos
O principal risco atual é de desempenho em bases maiores, devido ao custo linear temporário da estratégia utilizada antes da criação dos novos índices de família no Valkey.
Esse risco já está isolado para a próxima PAV de otimização.
Não foi introduzida alteração destrutiva de dados.
Rollback
O rollback pode ser feito revertendo os commits desta PR.
Não existem migrações destrutivas associadas a esta entrega.
Checklist
familyMode=primaryfamilyMode=anyanycomo modo padrãofamilyModeinválido retorna 400othernão é público/jobs/filters/optionsgit diff --checkfrontend/**front_admin/**scraper-go/**package-lock.json