Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
caf149f
feat(api): versiona documentação openapi
Jovinull Aug 28, 2026
0d2ce71
docs(repo): adicionar template padrão de pull request
Jovinull Aug 28, 2026
0ff4745
feat(api): completar contrato OpenAPI v1
Jovinull Aug 29, 2026
fe083dc
docs(repo): aplicar template revisado de pull request
Jovinull Aug 29, 2026
710a25f
feat(candidaturas): adicionar notas privadas múltiplas
Jovinull Aug 29, 2026
be9af8a
feat(segurança): aplica CSP restritiva
Jovinull Aug 30, 2026
174d2a4
fix(auth): corrige tipos de e-mail e provider
Jovinull Aug 30, 2026
7c9385b
feat(security): aplicar rate limit em POST /auth/register
Jovinull Sep 4, 2026
dd39c36
feat(security): adicionar HSTS e endurecer fallback de CORS em produção
Jovinull Sep 4, 2026
5d9bdee
docs(security): documentar hardening (rate limit, CORS, headers)
Jovinull Sep 4, 2026
99d6a1f
refactor(dashboard): reorganizar tiles principais do detalhe da vaga
Jovinull Sep 6, 2026
b5956a8
docs(dashboard): planejar reorganização do detalhe da candidatura
Jovinull Sep 6, 2026
b3dd96f
fix(dashboard): remover duplicação de dados no detalhe da vaga
Jovinull Sep 6, 2026
d7068c3
feat(dashboard): indicar quando as notas do detalhe são salvas
Jovinull Sep 6, 2026
dfb429b
docs(dashboard): registrar validação PASS da reorganização do detalhe
Jovinull Sep 6, 2026
f88bef1
docs(dashboard): registrar handoff da PAV-92 no STATE
Jovinull Sep 6, 2026
51a0d01
test(server): aumentar timeout do teste de boot sob suíte cheia
Jovinull Sep 6, 2026
4d077c2
feat(api): versiona documentação openapi (#234)
Benevanio Sep 7, 2026
8773457
PAV-92: Reorganizar detalhe da candidatura (#252)
Benevanio Sep 7, 2026
4ed9d91
PAV-34: Hardening de segurança (rate limit, CORS, headers) (#250)
Benevanio Sep 7, 2026
6dc09d9
[PAV-133] Corrigir tipagem em autenticação e conexões (#246)
Benevanio Sep 7, 2026
c90dc96
Merge remote-tracking branch 'origin/develop' into feature/pav-132-cs…
Benevanio Sep 7, 2026
1086986
[PAV-132] Mitigar DOM XSS e aplicar CSP restritiva (#245)
Benevanio Sep 7, 2026
d70ff35
Merge da develop em feature/pav-20-notas-privadas: resolve conflito n…
Benevanio Sep 7, 2026
4d108b9
feat(candidaturas): adicionar notas privadas múltiplas (#242)
Benevanio Sep 7, 2026
c127b3b
docs(repo): adicionar template padrão de pull request (#239)
Benevanio Sep 7, 2026
2e81528
feat(PAV-122): criar seed, atualizar docs e remover código morto
Benevanio Sep 7, 2026
9372c8e
feat(PAV-122): criar seed, atualizar docs e remover código morto
Benevanio Sep 7, 2026
bd4270d
chore: integrar develop e atualizar documentacao/tipos apos conflito …
Benevanio Sep 7, 2026
5ac60e5
docs(PAV-122): atualizar exemplos de variáveis de ambiente
Benevanio Sep 7, 2026
3579291
fix(PAV-122): permitir chamadas locais da API na CSP
Benevanio Sep 7, 2026
cbcbce2
docs(PAV-122): atualizar guia de desenvolvimento local
Benevanio Sep 7, 2026
f9e14b2
feat(PAV-122): criar seed e documentar testes locais da API (#254)
Benevanio Sep 20, 2026
983556b
feat(PAV-171): atualiza responsáveis pelo CODEOWNERS
Benevanio Sep 23, 2026
db4f32d
feat(PAV-171):atualiza responsáveis pelo CODEOWNERS (#255)
hltav Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 103 additions & 53 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,105 +1,155 @@
# Este arquivo é a fonte de variáveis de ambiente para o Docker Compose
# (docker-compose.yml injeta ./.env em backend e scraper-go via env_file).
# Copie para `.env` e preencha os segredos antes de subir o projeto.

# ---------------------------------------------------------------------------
# Runtime
# ---------------------------------------------------------------------------
NODE_ENV=development
PORT=3001

# Base URLs
# ---------------------------------------------------------------------------
# URLs base
# ---------------------------------------------------------------------------
APP_URL=http://localhost:3001
FRONTEND_URL=http://localhost:5173
GO_SCRAPER_URL=http://localhost:8081

# Session
# Use uma string longa e secreta em ambientes reais.
SESSION_SECRET=change-me-with-a-long-random-secret
# ---------------------------------------------------------------------------
# Sessão (backend) — obrigatória
# ---------------------------------------------------------------------------
# Qualquer string longa e aleatória. Gere uma com:
# node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
SESSION_SECRET=

# Segurança / PII
# ENCRYPTION_MASTER_KEY deve ter 32 bytes em hex, ou seja, 64 caracteres hex.
# ---------------------------------------------------------------------------
# Segurança / criptografia de PII (backend) — obrigatórias
# ---------------------------------------------------------------------------
# ENCRYPTION_MASTER_KEY precisa ter 64 caracteres hexadecimais (32 bytes).
# Gere uma com o mesmo comando acima.
ENCRYPTION_MASTER_KEY=
ENCRYPTION_KEY_ID=default
# Qualquer string secreta não vazia (usada para gerar hashes pesquisáveis de e-mail/CPF).
SEARCH_KEY=

# CORS / frontend access
# ---------------------------------------------------------------------------
# CORS (backend)
# ---------------------------------------------------------------------------
# Fonte da verdade das origens permitidas. Em produção, se vazio, cai apenas
# em *.candidate.app.br (localhost nunca entra por fallback em produção).
CORS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:5174

# Search filters
SEARCH_LOCATION=Brasil
SEARCH_GEO_ID=106057199
SEARCH_LANGUAGE=pt
REMOTE_ONLY=false
JOB_TYPES=C,F
TIME_FILTER=r604800
SEARCH_KEYWORDS=UX Designer,UI Designer,Product Manager,Product Owner
# ---------------------------------------------------------------------------
# Rate limit de autenticação (backend) — login e cadastro têm buckets próprios.
# Variável ausente ou inválida (<= 0 ou não numérica) usa o default indicado.
# ---------------------------------------------------------------------------
AUTH_RATE_LIMIT_IP_MAX=20
AUTH_RATE_LIMIT_ACCOUNT_MAX=5
AUTH_RATE_LIMIT_WINDOW_SECONDS=900

# Scraping behavior
SCRAPER_MAX_CONCURRENCY=12
SCRAPER_PROVIDER_MAX_CONCURRENCY=2
SCRAPER_PROVIDER_CONCURRENCY_OVERRIDES=
SCRAPER_RUN_LOCK_TTL=120s
SCRAPER_RUN_LOCK_RENEW_INTERVAL=30s
GOMAXPROCS=2
GOMEMLIMIT=1500MiB
WAIT_BETWEEN_SEARCHES_MS=5000
PAGE_TIMEOUT_MS=10000
MAX_PAGES_PER_KEYWORD=5

# Database / cache
# ---------------------------------------------------------------------------
# Banco de dados / cache
# ---------------------------------------------------------------------------
POSTGRES_USER=vagas
POSTGRES_PASSWORD=vagas
POSTGRES_DB=vagas

# Use esta URL quando backend/scraper estiverem rodando fora do Docker e o banco estiver exposto no host.
# Use esta URL quando backend/scraper rodarem fora do Docker e o banco/Valkey
# estiverem expostos no host (veja LOCAL_DEVELOPMENT.md para expor as portas).
DATABASE_URL=postgresql://vagas:vagas@localhost:5432/vagas
VALKEY_URL=redis://localhost:6379/0

# Use estas URLs dentro de containers Docker Compose.
# DATABASE_URL=postgresql://vagas:vagas@postgres:5432/vagas
# VALKEY_URL=redis://valkey:6379/0
# Dentro do Docker Compose, o backend/scraper-go já recebem
# VALKEY_URL=redis://valkey:6379/0 via `environment:` no docker-compose.yml,
# sobrescrevendo o valor acima — não precisa duplicar aqui.

CACHE_TTL_MS=600000
REDIS_KEY_PREFIX=vagas-full
KEYWORDS_REDIS_KEY=vagas-full:keywords
KEYWORDS_STORAGE_MODE=env
# Mantém GET /keywords ativo, mas bloqueia POST /keywords e publicação no kwsync.
# Liga/desliga POST /keywords no backend e o consumidor da fila
# scraper:keywords:pending no scraper-go (kwsync). Mantenha false em dev
# a menos que você esteja testando esse fluxo especificamente.
KWSYNC_ENABLED=false

# Legacy flags kept for compatibility
HEADLESS=false
VIEWPORT_WIDTH=1280
VIEWPORT_HEIGHT=800

# E-mail (módulo de e-mail transacional)
# EMAIL_API_KEY vazio => provider no-op (apenas loga, não envia). Preencha com a chave da Resend para enviar de verdade.
# ---------------------------------------------------------------------------
# E-mail transacional (backend)
# ---------------------------------------------------------------------------
# Vazio ⇒ provider no-op (apenas loga, não envia). Preencha com a chave da
# Resend para enviar de verdade.
EMAIL_API_KEY=
EMAIL_FROM_ADDRESS=
EMAIL_FROM_NAME=
# Tentativas de reenvio na fila de e-mail (backoff exponencial). Default: 3.
EMAIL_QUEUE_ATTEMPTS=3

# Third-party API credentials
# ---------------------------------------------------------------------------
# Integração backend <-> scraper-go
# ---------------------------------------------------------------------------
# Usada pelos adapters goScraper.ts/goKeywords.ts (fluxo de scraping/keywords direto).
GO_SCRAPER_URL=http://localhost:8081
# Usada pelo scraperClient nos endpoints administrativos /admin/scrapers/*.
# É uma variável distinta de GO_SCRAPER_URL, mesmo apontando ao mesmo serviço.
SCRAPER_URL=http://localhost:8081
# Endereço em que o próprio scraper-go escuta (opcional, default :8081).
GO_SCRAPER_ADDR=:8081

# ---------------------------------------------------------------------------
# Observabilidade
# ---------------------------------------------------------------------------
PROMETHEUS_URL=http://localhost:9090

# ---------------------------------------------------------------------------
# OAuth (opcional — só necessário para testar login social)
# ---------------------------------------------------------------------------
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

# ---------------------------------------------------------------------------
# Frontend / front_admin (usadas como build args pelo Docker Compose)
# ---------------------------------------------------------------------------
VITE_API_BASE_URL=http://localhost:3001
VITE_API_URL=http://localhost:3001
VITE_APP_ENV=development

# ---------------------------------------------------------------------------
# scraper-go — concorrência e limites de execução
# ---------------------------------------------------------------------------
SCRAPER_MAX_CONCURRENCY=12
SCRAPER_PROVIDER_MAX_CONCURRENCY=2
SCRAPER_PROVIDER_CONCURRENCY_OVERRIDES=
SCRAPER_RUN_LOCK_TTL=120s
SCRAPER_RUN_LOCK_RENEW_INTERVAL=30s
GOMAXPROCS=2
GOMEMLIMIT=1500MiB

# ---------------------------------------------------------------------------
# scraper-go — fontes de vagas de terceiros (todas opcionais)
# ---------------------------------------------------------------------------
ADZUNA_APP_ID=
ADZUNA_APP_KEY=
ADZUNA_KEYWORD_SLOT_SIZE=30
JOOBLE_API_KEY=
JOOBLE_API_BASE=https://br.jooble.org/api
THEMUSE_API_KEY=
LINKEDIN_KEYWORD_SLOT_SIZE=30
ADZUNA_KEYWORD_SLOT_SIZE=30

GUPY_ENABLED=true
GUPY_RAW_DISCOVERY_ENABLED=true
GUPY_FULL_SWEEP_ENABLED=true
GUPY_FULL_REMOTE_SWEEP_ENABLED=true
GUPY_QUERY_LIMIT=60

INHIRE_ENABLED=true
INHIRE_TENANTS_FILE=./internal/interfaces/inhireTenants.json
INHIRE_ENRICH_DETAILS=false
INHIRE_DETAILS_MODE=ambiguous
INHIRE_DETAILS_TIMEOUT_MS=10000

GREENHOUSE_ENABLED=true
GREENHOUSE_COMPANIES_FILE=./internal/interfaces/greenhouseCompanies.json

LEVER_ENABLED=false
LEVER_COMPANIES_FILE=./internal/interfaces/leverCompanies.json
LEVER_INCLUDE_ALL_JOBS=true

# OAuth credentials
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
10 changes: 7 additions & 3 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Responsaveis padrao para todos os diretorios do repositorio.
# Responsáveis gerais pelo repositório.
* @Benevanio @hltav

# Responsaveis por alteracoes dentro de /frontend.
/frontend/** @lima300 @nayarakarinesilva
# Frontend: responsáveis específicos pela área.
/frontend/** @pedrosilvaadev @nayarakarinesilva

# Configurações do GitHub e CI/CD.
/.github/** @Benevanio

112 changes: 112 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
## Linear

Issue: PAV-___

## Branch flow

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

## Objetivo

Descreva objetivamente o problema resolvido por esta PR.

## Escopo

O que faz parte desta entrega:

-

O que está fora do escopo:

-

## Resumo das alterações

-

## Arquivos e módulos afetados

-

## Como testar

```bash
# comandos de validação
```

## Validation

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

## Impacto de banco / migration

- [ ] Não altera schema nem migrations
- [ ] Altera schema ou migrations

Detalhes:

## Impacto em contratos/API

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

Detalhes:

## Impacto de configuração / infraestrutura

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

Detalhes:

## Impacto de segurança

- [ ] Sem impacto relevante
- [ ] Impacto de segurança avaliado

Detalhes:

## Impacto de dados pessoais / privacidade

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

Detalhes:

## Compatibilidade / dependências

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

Detalhes:

## Evidências

Adicione logs, screenshots, links de execução ou outra evidência relevante.

## Riscos

-

## Rollback

Descreva como a alteração pode ser revertida com segurança.

## Checklist final

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

> Consulte o guia de contribuição do projeto para as regras completas.
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
Expand All @@ -20,6 +22,15 @@ jobs:
- name: Instalar dependencias (raiz)
run: npm ci

- name: Validar mensagens de commit (commitlint)
# Backstop server-side: o hook local commit-msg pode ser pulado com `git commit --no-verify`,
# então o CI revalida todos os commits do PR antes de liberar o merge.
# Roda só em pull_request: commits de push para master/develop já chegaram via squash-merge
# do GitHub, cuja mensagem é o título do PR (padrão "[PAV-XXX] [Categoria] descrição",
# ver GUIA-LINEAR-GITHUB.md) — um formato diferente e fora do controle de quem contribui.
if: github.event_name == 'pull_request'
run: npx commitlint --from "${{ github.event.pull_request.base.sha }}" --to "${{ github.event.pull_request.head.sha }}" --verbose

- name: Workaround npm optional deps (rollup linux)
run: npm i --no-save --workspace=frontend @rollup/rollup-linux-x64-gnu

Expand Down
12 changes: 7 additions & 5 deletions .specs/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ Active project-level architectural decisions (AD-NNN). Each design must conform

## Handoff

**Feature concluída:** `email-module` (PAV-76) — ✅ Done.
**Estado:** 11/11 tasks implementadas e commitadas na branch `feature/pav-76-modulo-email` (Batch A: 5 commits; Batch B: 6 commits). Verifier PASS (11/11 ACs, gate 529/0, sensor 5/5 mutantes mortos). Relatório em `.specs/features/email-module/validation.md`.
**Entregue:** API interna `emailService.send/sendWelcome`, fila BullMQ/Valkey (ioredis), worker in-process, `MailProvider`+Resend+Noop, template `welcome` react-email com CTA (`FRONTEND_URL`), boas-vindas no registro (`CredentialsService.register`), docs no `BACKEND.md`.
**Pendências deixadas ao usuário:** (1) push + PR ainda NÃO feitos (a pedido); (2) envs de produção `EMAIL_API_KEY`/`EMAIL_FROM_ADDRESS`/`EMAIL_FROM_NAME` a comunicar ao dev quando for pra prod — sem elas o `NoopProvider` só loga.
**Próximo passo:** quando o usuário pedir, abrir PR da PAV-76.
**Feature concluída:** `job-detail-reorganizacao` (PAV-92) — ✅ Done.
**Estado:** implementada e commitada na branch `jovinull/pav-92-frontend` (4 commits: reorg de tiles, dedup do payload, feedback de notas, docs). Validação standalone PASS (8/8 ACs, gate 352/352 frontend, sensor de mutação raciocinado sem sobreviventes). Relatório em `.specs/features/job-detail-reorganizacao/validation.md`.
**Entregue:** `JobDetailModal` reorganizado — local/modalidade/nível/fonte/salário/match em tiles rotulados; bloco "Payload da vaga" renomeado para "Detalhes adicionais" e sem duplicar dado já mostrado; texto indicando que notas salvam ao fechar. Sem migração de modal pra página (critério do próprio card já resolvia isso) e sem novo contrato de backend.
**Pendências deixadas ao usuário:** push + PR ainda NÃO feitos (aguardando confirmação do usuário).
**Próximo passo:** quando o usuário pedir, abrir PR da PAV-92.

**Feature anterior concluída:** `email-module` (PAV-76) — ✅ Done. 11/11 tasks, branch `feature/pav-76-modulo-email`, Verifier PASS (11/11 ACs, gate 529/0, sensor 5/5). Entregue: `emailService.send/sendWelcome`, fila BullMQ/Valkey, `MailProvider`+Resend+Noop, template `welcome`, boas-vindas no registro. Envs de produção `EMAIL_API_KEY`/`EMAIL_FROM_ADDRESS`/`EMAIL_FROM_NAME` a comunicar ao dev quando for pra prod.
Loading
Loading