Skip to content

PAV-117: [Frontend] Implementar filtros avançados e contrato de familias - #326

Merged
Benevanio merged 10 commits into
Cla-Code-Community:developfrom
GiovanniDonati:master
Oct 15, 2026
Merged

Benevanio merged 10 commits into
Cla-Code-Community:developfrom
GiovanniDonati:master

Conversation

@GiovanniDonati

Copy link
Copy Markdown
Collaborator

Descrição

Implementado os filtros avançados estipulados pelo backend, além de integrar o novo contrato e filtro de familias, seguindo todos os critérios de aceite definidos no card.

Linear:

https://linear.app/candidateappbr/issue/PAV-117/frontend-implementar-filtro-inteligente-por-areas-de-tecnologia

Testes:

  • Realizado os testes unitários do frontend
  • Realizado a validação dos filtros

Benevanio and others added 10 commits October 7, 2026 09:09
…as na API (Cla-Code-Community#291)

## 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`
## Branch flow

- [x] Este PR é uma chore destinada a `master`.
- [x] Este PR não contém alteração direta ou fluxo indevido para
`master`.
- [x] A branch foi criada a partir da base prevista pelo fluxo do
projeto.

## Objetivo

Ajustar a configuração do Dependabot para que as atualizações
automáticas de dependências sejam direcionadas para a branch `develop`,
alinhando o fluxo de atualizações automáticas ao fluxo atual de
desenvolvimento do projeto.

## Escopo

O que faz parte desta entrega:

- Alterar a branch alvo do Dependabot para `develop`.
- Aplicar a alteração aos ecossistemas `npm`, `github-actions`, `gomod`
e `docker`.
- Manter a frequência mensal das atualizações.
- Manter os limites atuais de Pull Requests.
- Manter o agrupamento de atualizações `minor` e `patch` do npm.

O que está fora do escopo:

- Alteração das dependências do projeto.
- Alteração do código-fonte da aplicação.
- Alteração da estratégia de deploy.
- Alteração das configurações de `master`.

## Resumo das alterações

- Alterado `target-branch` de todas as configurações do Dependabot para
`develop`.
- Mantidas as configurações existentes de frequência, limites de PRs e
agrupamento de atualizações.

## Arquivos e módulos afetados

- `.github/dependabot.yml`

## Como testar

```bash
# Validar a configuração alterada
git diff --check

# Conferir a alteração
git diff -- .github/dependabot.yml

# Conferir a branch atual
git branch --show-current
````

## Validation

* [x] Lint executado
* [ ] Testes relevantes executados
* [ ] Coverage permanece dentro do mínimo do projeto
* [ ] Build executado quando aplicável
* [x] Validação manual realizada quando aplicável
* [x] Documentação atualizada quando necessária

## Impacto de banco / migration

* [x] Não altera schema nem migrations
* [ ] Altera schema ou migrations

Detalhes:

Não há alterações relacionadas a banco de dados ou migrations.

## Impacto em contratos/API

* [x] Não altera contratos
* [ ] Altera endpoint, payload, schema ou comportamento de API

Detalhes:

Não há alterações em endpoints, payloads, schemas ou contratos de API.

## Impacto de configuração / infraestrutura

* [ ] Não altera configuração
* [x] Altera env, Docker, filas, cache, serviços ou infraestrutura

Detalhes:

Altera exclusivamente a configuração do Dependabot em
`.github/dependabot.yml`, direcionando seus PRs para `develop`. Não há
alteração em Docker, ambientes, filas, cache ou serviços da aplicação.

## Impacto de segurança

* [x] Sem impacto relevante
* [ ] Impacto de segurança avaliado

Detalhes:

A alteração não modifica código de aplicação, autenticação, autorização,
credenciais ou dados sensíveis.

## Impacto de dados pessoais / privacidade

* [x] Sem tratamento novo ou alteração de dados pessoais
* [ ] Impacto avaliado

Detalhes:

A alteração não envolve tratamento ou armazenamento de dados pessoais.

## Compatibilidade / dependências

* [x] Não depende de outra task/PR
* [ ] Existe dependência ou ordem de deploy/merge

Detalhes:

A alteração é independente e está restrita à configuração do Dependabot.

## Evidências

* Configuração `.github/dependabot.yml` revisada.
* `target-branch` configurado como `develop` para todos os ecossistemas.
* `git diff --check` utilizado para validação da alteração.

## Riscos

* Baixo risco.
* O principal impacto possível é o Dependabot passar a abrir
atualizações na branch `develop`, conforme definido no card.
* As demais regras de atualização foram mantidas.

## Rollback

Reverter o commit desta PR ou restaurar os valores anteriores de
`target-branch` no arquivo `.github/dependabot.yml`.

## Checklist final

* [x] Escopo limitado ao card
* [x] Não inclui segredos, `.env`, certificados ou tokens
* [x] Não inclui arquivos temporários, builds, caches ou artefatos
desnecessários
* [x] Não executa deploy como efeito desta PR
* [x] Critérios de aceite do card foram conferidos individualmente
* [x] Alterações de contrato possuem testes e documentação
correspondentes
* [x] Alterações em banco/migrations foram validadas quando aplicável

> Consulte o guia de contribuição do projeto para as regras completas.

```
```
````markdown
## Linear

Issue: PAV-176

## Branch flow

- [x] Este PR é uma chore destinada a `develop`.
- [x] Este PR não contém alteração direta ou fluxo indevido para `master`.
- [x] A branch foi criada a partir da base prevista pelo fluxo do projeto.

## Objetivo

Ajustar a configuração do Dependabot para que as atualizações automáticas de dependências sejam direcionadas para a branch `develop`, alinhando o fluxo de atualizações automáticas ao fluxo atual de desenvolvimento do projeto.

## Escopo

O que faz parte desta entrega:

- Alterar a branch alvo do Dependabot para `develop`.
- Aplicar a alteração aos ecossistemas `npm`, `github-actions`, `gomod` e `docker`.
- Manter a frequência mensal das atualizações.
- Manter os limites atuais de Pull Requests.
- Manter o agrupamento de atualizações `minor` e `patch` do npm.

O que está fora do escopo:

- Alteração das dependências do projeto.
- Alteração do código-fonte da aplicação.
- Alteração da estratégia de deploy.
- Alteração das configurações de `master`.

## Resumo das alterações

- Alterado `target-branch` de todas as configurações do Dependabot para `develop`.
- Mantidas as configurações existentes de frequência, limites de PRs e agrupamento de atualizações.

## Arquivos e módulos afetados

- `.github/dependabot.yml`

## Como testar

```bash
# Validar a configuração alterada
git diff --check

# Conferir a alteração
git diff -- .github/dependabot.yml

# Conferir a branch atual
git branch --show-current
````

## Validation

* [x] Lint executado
* [ ] Testes relevantes executados
* [ ] Coverage permanece dentro do mínimo do projeto
* [ ] Build executado quando aplicável
* [x] Validação manual realizada quando aplicável
* [x] Documentação atualizada quando necessária

## Impacto de banco / migration

* [x] Não altera schema nem migrations
* [ ] Altera schema ou migrations

Detalhes:

Não há alterações relacionadas a banco de dados ou migrations.

## Impacto em contratos/API

* [x] Não altera contratos
* [ ] Altera endpoint, payload, schema ou comportamento de API

Detalhes:

Não há alterações em endpoints, payloads, schemas ou contratos de API.

## Impacto de configuração / infraestrutura

* [ ] Não altera configuração
* [x] Altera env, Docker, filas, cache, serviços ou infraestrutura

Detalhes:

Altera exclusivamente a configuração do Dependabot em `.github/dependabot.yml`, direcionando seus PRs para `develop`. Não há alteração em Docker, ambientes, filas, cache ou serviços da aplicação.

## Impacto de segurança

* [x] Sem impacto relevante
* [ ] Impacto de segurança avaliado

Detalhes:

A alteração não modifica código de aplicação, autenticação, autorização, credenciais ou dados sensíveis.

## Impacto de dados pessoais / privacidade

* [x] Sem tratamento novo ou alteração de dados pessoais
* [ ] Impacto avaliado

Detalhes:

A alteração não envolve tratamento ou armazenamento de dados pessoais.

## Compatibilidade / dependências

* [x] Não depende de outra task/PR
* [ ] Existe dependência ou ordem de deploy/merge

Detalhes:

A alteração é independente e está restrita à configuração do Dependabot.

## Evidências

* Configuração `.github/dependabot.yml` revisada.
* `target-branch` configurado como `develop` para todos os ecossistemas.
* `git diff --check` utilizado para validação da alteração.

## Riscos

* Baixo risco.
* O principal impacto possível é o Dependabot passar a abrir atualizações na branch `develop`, conforme definido no card.
* As demais regras de atualização foram mantidas.

## Rollback

Reverter o commit desta PR ou restaurar os valores anteriores de `target-branch` no arquivo `.github/dependabot.yml`.

## Checklist final

* [x] Escopo limitado ao card
* [x] Não inclui segredos, `.env`, certificados ou tokens
* [x] Não inclui arquivos temporários, builds, caches ou artefatos desnecessários
* [x] Não executa deploy como efeito desta PR
* [x] Critérios de aceite do card foram conferidos individualmente
* [x] Alterações de contrato possuem testes e documentação correspondentes
* [ ] Alterações em banco/migrations foram validadas quando aplicável
…rminístico e match score (Cla-Code-Community#308)

## Linear

[PAV-125 — Backend/Valkey: Implementar índices por família, cache
determinístico e match
score](https://linear.app/candidateappbr/issue/PAV-125)

## 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:

    PostgreSQL = source of truth do catálogo de vagas
    Valkey     = índices, cache e camada de leitura otimizada

O Processor passa a persistir a vaga no PostgreSQL antes de publicar ou
atualizar seus índices no Valkey.

Fluxo principal:

    coleta
      ↓
    classificação
      ↓
    persistência PostgreSQL
      ↓
    COMMIT confirmado
      ↓
    indexação Valkey
      ↓
    busca/cache

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:

- upsert idempotente;
- primeira coleta;
- última observação;
- atualização;
- expiração;
- controle de revisão;
- identificação de vagas ainda não indexadas;
- rebuild e reconciliação.

Migration adicionada:

    backend/drizzle/0015_job_catalog.sql

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:

- mantém o mesmo ID;
- realiza upsert;
- atualiza a última observação;
- renova sua expiração;
- persiste a nova classificação quando necessário;
- reindexa somente após o commit.

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:

    scraper:jobs:family:<family>

Compatibilidade com busca `any`, contendo primary ou related.

    scraper:jobs:family:primary:<family>

Somente vagas cuja família principal corresponde à família consultada.

    scraper:jobs:family:related:<family>

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.

`other` permanece 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:

    other → product
    product → product_design

ou alterações simultâneas de família principal e famílias relacionadas.

A publicação usa operação Lua no Valkey para:

- validar previamente os tipos das chaves envolvidas;
- remover associações antigas da vaga;
- adicionar as novas associações;
- atualizar seu registro inverso;
- preservar idempotência em retries;
- atualizar a geração do cache somente após sucesso.

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:

- uma família;
- múltiplas famílias;
- `familyMode=any`;
- `familyMode=primary`;
- OR entre famílias;
- AND com os demais filtros.

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`;
- página;
- ordenação.

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:

- famílias normalizadas;
- `familyMode`;
- senioridade;
- modalidade;
- localização;
- contrato;
- texto;
- provider;
- tecnologias;
- paginação;
- ordenação;
- contexto de ranking;
- versão/geração dos índices.

As famílias são:

- normalizadas;
- deduplicadas;
- ordenadas.

Portanto, por exemplo:

    backend,fullstack

e:

    fullstack,backend,backend

produzem o mesmo fingerprint.

`familyMode=primary` e `familyMode=any` produzem 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`;
- limpeza global do Valkey.

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:

    PostgreSQL
      ↓
    leitura em batches
      ↓
    vagas ativas
      ↓
    namespace Valkey novo
      ↓
    validação
      ↓
    troca da versão ativa

O rebuild:

- não depende de nova coleta externa;
- não carrega todo o catálogo em memória;
- é cancelável;
- é idempotente;
- trabalha em batches;
- não utiliza `KEYS`;
- não utiliza `FLUSHALL` ou `FLUSHDB`;
- mantém o namespace anterior disponível durante a troca.

---

## Reconciliação

Foi adicionada reconciliação entre:

    PostgreSQL
    ↕
    Valkey

Ela detecta situações como:

- vaga ativa sem índice;
- ID stale no Valkey;
- vaga inativa ainda indexada;
- família primary divergente;
- related divergente;
- membership divergente;
- índice `any` incorreto;
- taxonomia inválida.

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:

- é explicitamente acionado;
- trabalha em batches;
- é idempotente;
- pode ser repetido;
- respeita cancelamento;
- não utiliza `KEYS`;
- não executa automaticamente no startup normal.

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:

    scraper-go/cmd/catalog/

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:

- família;
- senioridade;
- modalidade;
- localização;
- competências;
- ferramentas;
- termos de produto.

Para Product Design são consideradas evidências relacionadas a:

- UX/UI;
- pesquisa;
- prototipação;
- design systems;
- acessibilidade;
- Figma e ferramentas equivalentes.

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 `matchReasons` opcional 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:

- `jobTypes` representa `Remoto`, `Híbrido` e `Presencial`;
- `remoteOnly` representa preferência por remoto;
- `searchLocation` representa localização de busca;
- `keywords` contém texto livre.

Por isso:

- `jobTypes` permanece utilizado como modalidade;
- valores legados incompatíveis são ignorados;
- `keywords` não é usado para inferir família profissional;
- `contract` não é inferido porque não existe atualmente fonte segura no
modelo;
- `family` també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`;
- múltiplas famílias;
- `familyMode`;
- default `any`;
- validação canônica;
- erros existentes;
- paginação;
- ordenação;
- autenticação;
- rate limit;
- endpoint `/jobs/filters/options`.

Também foram preservados:

- IDs atuais das vagas;
- saved jobs;
- comportamento das demais famílias;
- fallback para os índices anteriores durante a migração.

Não há alterações em:

- `frontend/**`;
- `front_admin/**`;
- `package-lock.json`.

---

## Principais arquivos

### PostgreSQL

    backend/src/db/schema/jobCatalog.ts
    backend/drizzle/0015_job_catalog.sql
    backend/drizzle/meta/0015_snapshot.json

### Processor

    scraper-go/internal/catalog/
    scraper-go/internal/catalogops/
    scraper-go/internal/jobindex/
    scraper-go/cmd/catalog/

### Backend / busca

    backend/src/modules/jobs/cache/
    backend/src/modules/jobs/repositories/valkeyJobSearch.adapter.ts
    backend/src/modules/jobs/repositories/jobSearch.repository.ts

### Match

    backend/src/modules/jobs/services/jobMatch.service.ts
    backend/src/modules/jobs/services/jobProfileMatch.service.ts

### Documentação

    BACKEND.md
    SCRAPER.md
    backend/PAV-125_REPORT.md

---

## Testes e validações

Validações executadas durante a implementação:

- 826 testes do backend aprovados;
- testes Go aprovados;
- `go test -race` aprovado;
- `go vet` aprovado;
- TypeScript typecheck aprovado;
- Swagger validado;
- Docker Compose validado;
- build da CLI aprovado;
- `git diff --check` aprovado.

Também foram executados testes de integração com PostgreSQL e
Redis/Valkey isolados.

Os testes cobrem, entre outros:

- insert;
- upsert;
- rollback;
- falha de commit;
- não indexar antes do commit;
- reclassificação;
- membership inverso;
- primary/related/any;
- rebuild;
- reconciliação;
- cache;
- fingerprint;
- invalidação;
- paginação;
- match de Produto;
- match de Product Design;
- separação entre modalidade, contrato e família.

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:

    /jobs/search p95 < 500 ms

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:

1. aplicar a migration PostgreSQL;
2. validar o schema;
3. executar o backfill controlado;
4. executar rebuild dos índices;
5. executar reconciliação;
6. validar contagens/divergências;
7. ativar/trocar o namespace Valkey;
8. ativar o novo Processor.

O PostgreSQL é a fonte de verdade.

O Valkey pode ser reconstruído a partir dele.

---

## Rollback

Em caso de problema durante a ativação:

- manter/reverter para o namespace Valkey anterior;
- interromper o novo Processor;
- preservar o catálogo PostgreSQL;
- não executar limpeza global do Valkey;
- corrigir/reexecutar rebuild ou reconciliação;
- reativar o novo namespace somente após validaçã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:

- novas métricas Prometheus completas;
- dashboard administrativo;
- alterações visuais;
- filtros no frontend;
- mudanças em `frontend/**`;
- mudanças visuais em `front_admin/**`;
- correção de `package-lock`;
- alteração geral do match score das demais famílias;
- política de deleção histórica;
- Redis Cluster;
- worker/outbox dedicado.

---

## Checklist

- [x] PostgreSQL como source of truth
- [x] persistência antes da indexação
- [x] índices `primary`
- [x] índices `related`
- [x] índice compatível com `any`
- [x] membership inverso
- [x] reclassificação idempotente
- [x] cache determinístico
- [x] invalidação por geração
- [x] rebuild
- [x] reconciliação
- [x] backfill controlado
- [x] match Product/Product Design
- [x] contratos da PAV-124 preservados
- [x] sem `KEYS`, `FLUSHALL` ou `FLUSHDB`
- [x] sem alterações em frontend/front_admin/package-lock
- [x] testes backend
- [x] testes Go
- [x] race
- [x] vet
- [x] typecheck
- [x] `git diff --check`
- [ ] validação de p95 < 500 ms em ambiente representativo
…ificação e indexação (Cla-Code-Community#311)

## Release

Promove para produção as alterações da PAV-126 já aprovadas e mergeadas
em `develop`.

## Conteúdo

PAV-126 — Observabilidade completa do scraper, classificação e
indexação.

Principais entregas:

- observabilidade operacional completa do Jobs Processor;
- métricas de execução, progresso e concorrência;
- métricas de lock distribuído;
- métricas de classificação;
- métricas de persistência PostgreSQL;
- métricas de indexação Valkey;
- métricas de cache e busca;
- endpoint administrativo de observabilidade;
- disponibilidade parcial do snapshot operacional;
- 14 recording rules;
- 16 alertas;
- normalização de labels e controle de cardinalidade;
- melhorias nas métricas HTTP;
- telemetria de rebuild e reconciliação;
- documentação e configuração Prometheus atualizadas.

## Validações realizadas

- `go test ./...`
- `go test -race ./...`
- `go vet ./...`
- 848 testes do backend aprovados
- TypeScript validado
- Swagger validado
- Prometheus e regras validados com `promtool`
- Docker Compose validado
- `git diff --check` aprovado

## Produção

Após o deploy, validar:

- ciclo completo do scraper;
- endpoint administrativo de observabilidade;
- CPU e memória;
- lock e progresso;
- cardinalidade das métricas;
- comportamento dos alertas;
- latência de `/jobs/search`;
- latência do endpoint administrativo;
- integração do Alertmanager.

A meta de p95 < 500 ms deverá ser validada com carga representativa em
produção/staging.

## Origem

`develop` → `master`

PR de implementação:

PAV-126: [Observabilidade] Expor métricas completas do scraper,
classificação e indexação (Cla-Code-Community#310)
…as de classificação (Cla-Code-Community#314)

Linear
PAV-127 — [Front Admin] Implementar dashboard Scraper Health e métricas
de classificação

Objetivo
Implementar no Front Admin uma visão operacional completa do Jobs
Processor, consumindo os contratos de observabilidade existentes e
expondo de forma clara o estado de execução, saúde dos serviços,
progresso do pipeline, providers, catálogo e métricas de classificação.

A entrega também consolida ajustes necessários no backend e no Jobs
Processor para suportar os dados consumidos pelo painel administrativo e
reorganiza os arquivos Docker Compose utilizados no ambiente local.

Resumo das alterações
A PAV-127 transforma o Front Admin em uma interface operacional para
acompanhamento do Jobs Processor.

A implementação adiciona e refina:

visão geral de saúde da plataforma;
estado atual do Jobs Processor;
execução atual e run_id;
origem e estágio da execução;
lock distribuído;
concorrência global e por provider;
progresso do pipeline;
métricas de coleta;
métricas de classificação;
métricas de persistência;
métricas de indexação;
catálogo de vagas persistidas;
resumo operacional de providers;
polling compartilhado e cancelável;
tratamento de dados parciais, indisponíveis e stale;
distinção entre valor 0 e dado indisponível;
melhorias de UX na tela de Observabilidade;
melhorias de UX na tela de Processamento de Vagas;
integração entre Front Admin, backend e Jobs Processor.
Front Admin
Observabilidade
A tela de Observabilidade foi reorganizada para priorizar o estado
operacional atual.

Foram adicionadas ou refinadas as seções de:

Saúde geral;
Execução atual do Processor;
Pipeline;
Infraestrutura;
métricas operacionais;
histórico.
A visão de saúde apresenta de forma compacta o estado de:

API;
PostgreSQL;
Valkey;
Jobs Processor;
taxa de erro HTTP;
latência HTTP p95.
A execução atual apresenta informações como:

run_id;
estágio;
duração;
lock;
concorrência;
progresso da execução.
O pipeline passou a representar de forma explícita:

Coleta;
Classificação;
Persistência;
Indexação.
Também foi implementado tratamento visual consistente para:

dados indisponíveis;
dados parciais;
snapshots stale;
valor zero válido.
Polling operacional
Foi criada uma camada compartilhada de polling para evitar múltiplas
consultas concorrentes ao mesmo recurso.

O polling:

compartilha o snapshot entre consumidores;
permite cancelamento;
controla atualização periódica;
trata falhas de API;
evita duplicação de requisições entre telas.
Processamento de Vagas
A antiga visão de Scrapers foi refinada para representar melhor o
domínio operacional.

Na interface:

o menu passou a utilizar o nome Processamento;
a página utiliza o título Processamento de Vagas;
referências internas de rota e código continuam compatíveis com
scrapers.
A tela passou a apresentar informações operacionais dos providers de
forma estruturada.

A tabela da execução exibe:

provider;
tarefas;
vagas coletadas;
falhas;
tarefas ativas ou em espera;
último resultado;
detalhes expansíveis.
Catálogo
Os cards de catálogo passaram a utilizar os totais reais persistidos no
PostgreSQL.

O PostgreSQL é tratado como fonte de verdade do catálogo.

O Valkey permanece como camada de índice/cache e não é utilizado como
fonte de verdade para a quantidade total de vagas persistidas.

Combinações equivalentes de fontes/providers são normalizadas de forma
determinística.

Exemplos equivalentes:

Adzuna,Gupy;
Gupy,Adzuna;
Adzuna,Gupy,Adzuna.
Essas combinações passam a representar um único agrupamento lógico, com
contagem agregada.

Backend
Foram realizados ajustes no contrato administrativo utilizado pelo Front
Admin.

As alterações incluem:

extensão dos tipos de observabilidade;
ajustes no cliente do Jobs Processor;
suporte aos dados utilizados pelo snapshot operacional;
suporte às contagens utilizadas pelo catálogo;
testes adicionais dos contratos administrativos.
Jobs Processor
O Jobs Processor foi ajustado para fornecer dados adicionais necessários
ao Front Admin.

Foram incluídos ou refinados:

snapshot da execução atual;
métricas associadas ao run_id;
estado do pipeline;
contagem de vagas por origem;
informações utilizadas pelo catálogo;
dados operacionais de providers;
testes do snapshot;
testes das contagens por origem.
A implementação mantém o snapshot operacional em memória.

Consequentemente, o snapshot representa a execução observada pela
instância atual e pode ser reiniciado junto com o processo.

As métricas operacionais representam eventos observados durante o
processamento e não devem ser interpretadas automaticamente como
contagem de entidades únicas.

Docker / ambiente local
A organização dos arquivos Docker Compose foi consolidada.

Os arquivos específicos foram movidos para:

docker/docker-compose.app.yml;
docker/docker-compose.infra.yml;
docker/docker-compose.migrate.yml;
docker/docker-compose.observability.yml.
Também foi adicionado:

docker-full.docker-compose.yml.
O docker-compose.yml principal foi ajustado para acompanhar essa
organização.

Essa alteração reduz a dispersão dos arquivos de ambiente e deixa mais
explícita a separação entre aplicação, infraestrutura, migração e
observabilidade.

Compatibilidade
A implementação preserva:

rotas administrativas existentes;
nomenclaturas internas necessárias para compatibilidade;
contratos já entregues pelas PAVs anteriores;
funcionamento do Jobs Processor;
PostgreSQL como fonte de verdade do catálogo;
Valkey como índice/cache.
A mudança de nomenclatura de Scrapers para Processamento é apenas de
interface.

Não houve renomeação estrutural de rotas ou módulos internos nesta
entrega.

Testes
A suíte do Front Admin foi executada com cobertura.

Resultado:

47 arquivos de teste aprovados;
212 testes aprovados;
cobertura global de statements: 95,72%;
cobertura global de branches: 87,81%;
cobertura global de functions: 96,29%;
cobertura global de lines: 98,29%.
Entre os componentes principais:

ObservabilityPage.tsx: 100% de statements, functions e lines;
OperationalSnapshotPanels.tsx: 100% de statements, functions e lines;
ScrapersPage.tsx: 100% de statements, functions e lines.
Também foram validados anteriormente os contratos e testes relacionados
no backend e no Jobs Processor.

Foi executado:

git diff --check.
Não foram encontrados erros de whitespace no diff preparado para commit.

Arquivos principais
Front Admin
front_admin/src/modules/observability/**
front_admin/src/modules/scrapers/**
front_admin/src/modules/dashboard/**
front_admin/src/lib/polling/**
front_admin/src/lib/api/**
testes correspondentes em front_admin/tests/**
Backend
backend/src/modules/admin/observability/**
backend/src/modules/admin/scrapers/**
testes administrativos relacionados
Jobs Processor
scraper-go/cmd/server/**
scraper-go/internal/catalog/**
scraper-go/internal/jobstore/**
scraper-go/internal/metrics/**
scraper-go/internal/pipeline/**
Docker
docker-compose.yml
docker-full.docker-compose.yml
docker/docker-compose.app.yml
docker/docker-compose.infra.yml
docker/docker-compose.migrate.yml
docker/docker-compose.observability.yml
Fora do escopo
Esta entrega não inclui:

renomeação estrutural de scraper-go;
renomeação das rotas internas /admin/scrapers;
persistência histórica do snapshot operacional;
transformação do snapshot em armazenamento permanente;
utilização do Valkey como fonte de verdade do catálogo.
Riscos
O snapshot operacional do Jobs Processor é mantido em memória.

Em caso de reinicialização da instância, o estado da execução
anteriormente observada não permanece disponível no snapshot atual.

Algumas métricas representam eventos acumulados do processamento e não
necessariamente entidades únicas.

Essas características são refletidas na apresentação do Front Admin para
evitar interpretação incorreta dos dados.

Rollback
O rollback pode ser realizado revertendo o commit desta PR.

Não existem migrações destrutivas de banco de dados associadas a esta
entrega.

Checklist
 Dashboard operacional integrado
 Saúde geral dos serviços
 Estado atual do Jobs Processor
 run_id exibido
 Estágio da execução exibido
 Lock distribuído representado
 Concorrência representada
 Pipeline de coleta
 Pipeline de classificação
 Pipeline de persistência
 Pipeline de indexação
 Métricas de classificação
 Polling compartilhado
 Tratamento de estado stale
 Tratamento de dados parciais
 Distinção entre 0 e indisponível
 Tela de Processamento de Vagas refinada
 Providers da execução estruturados
 Catálogo baseado em PostgreSQL
 Combinações de providers normalizadas
 Backend administrativo atualizado
 Snapshot do Processor atualizado
 Contagens por origem implementadas
 Testes do Front Admin
 212 testes aprovados
 Cobertura acima de 80%
 Docker Compose reorganizado
 git diff --check
PAV-117: [Frontend] Implementar filtros avançados e contrato de familias

## Descrição
Implementado os filtros avançados estipulados pelo backend, além de integrar o novo contrato e filtro de familias, seguindo todos os critérios de aceite definidos no card.

## Linear:
[https://linear.app/candidateappbr/issue/PAV-117/frontend-implementar-filtro-inteligente-por-areas-de-tecnologia](https://linear.app/candidateappbr/issue/PAV-117/frontend-implementar-filtro-inteligente-por-areas-de-tecnologia)

## Testes:
- Realizado os testes unitários do frontend
- Realizado a validação dos filtros
## Descrição
Implementado os filtros avançados estipulados pelo backend, além de integrar o novo contrato e filtro de familias, seguindo todos os critérios de aceite definidos no card.

## Linear:
[https://linear.app/candidateappbr/issue/PAV-117/frontend-implementar-filtro-inteligente-por-areas-de-tecnologia](https://linear.app/candidateappbr/issue/PAV-117/frontend-implementar-filtro-inteligente-por-areas-de-tecnologia)

## Testes:
- Realizado os testes unitários do frontend
- Realizado a validação dos filtros
@Benevanio
Benevanio merged commit 879e4b4 into Cla-Code-Community:develop Oct 15, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in JobAtlas – Kanban Oct 15, 2026
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.

3 participants