Skip to content

Feature/listagem vagas supabase - #4

Merged
dannyserena merged 14 commits into
mainfrom
feature/listagem-vagas-supabase
Sep 22, 2026
Merged

dannyserena merged 14 commits into
mainfrom
feature/listagem-vagas-supabase

Conversation

@dannyserena

Copy link
Copy Markdown
Member

Update permite usar o projeto atraves do gitgub codespace

dannyserena and others added 14 commits September 1, 2026 17:30
- Nova migration 002_create_core_tables.sql: tabelas users, companies e
  applications (RLS habilitado), extensão pgvector (nome correto: vector)
  e extensão retrocompativel de jobs (company_id, embedding vector(384)).
- jobs (001) permanece intocada para não quebrar dados já em produção no
  Supabase; a nova migration só adiciona colunas nullable.
- schema.sql agora aponta para as migrations em ordem, como referência
  única do schema atual.
- README do package/database documentado: modelo relacional, por que RLS
  aqui não usa auth.uid() (auth é Firebase, não Supabase Auth) e como
  aplicar a migration local (Docker) ou no Supabase real (SQL Editor /
  supabase db push).
- Validado de ponta a ponta: subi o Postgres local (pgvector/pg16 do
  docker-compose.yml), rodei 001 + 002 + seeds/jobs.sql sem erros,
  confirmei tabelas, FKs, policies e extensão vector instalada.
- npm run db:migrate:local roda essa validação; db:migrate passou a
  apontar o caminho certo em vez do TODO antigo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- getJobs agora usa .select('*', { count: 'exact' }) + .range(from, to)
  do Supabase para paginar no servidor (limit/offset reais, não paginação
  client-side), mantendo os filtros de modalidade/senioridade/tech/busca
  já existentes.
- Retorno passou de Job[] para PaginatedJobs (jobs, page, pageSize,
  totalCount, totalPages) — JOBS_PAGE_SIZE = 20.
- Novo componente Pagination (Server Component): links 'Anterior/Próxima'
  e indicador 'Página X de Y', preservando os filtros atuais da URL.
- JobsPage lê ?page= dos searchParams e repassa pro getJobs; renderiza
  <Pagination /> abaixo da lista de vagas.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- lib/ai.ts: cliente Gemini (@google/generative-ai) com structured output
  (responseSchema) forçando o retorno a um JSON com search/modality/
  seniority/tech — validado de novo no nosso lado com zod antes de usar.
  Lança AiNotConfiguredError se GEMINI_API_KEY não estiver no .env.local.
- Novo endpoint POST /api/jobs/ai-search: recebe { query } em linguagem
  natural (ex: 'vaga remota React sênior') e devolve { filters } prontos
  pra aplicar nos mesmos filtros da Feature 1.
- Novo componente AiSearchBar (client): chama o endpoint e navega pra
  /jobs?... com os filtros retornados, reaproveitando o pipeline server-side
  de getJobs (filtros + paginação) já existente. Mostra erro amigável se a
  IA não estiver configurada ou a resposta não puder ser interpretada.
- JobsPage passa a renderizar a AiSearchBar acima do JobFilters.
- .env.example documentado com GEMINI_API_KEY / GEMINI_MODEL.

Chave ainda não configurada neste ambiente — endpoint testado apenas até a
validação de entrada (400) e do erro 503 de 'IA não configurada'; a
extração real do Gemini fica para ser validada com a chave em mãos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Achado testando de ponta a ponta contra o Supabase real:
- Pedir uma página cujo offset passa do total de linhas (ex: ?page=2 com
  só 15 vagas) fazia o PostgREST devolver PGRST103 ('Requested range not
  satisfiable') e a página quebrava com 500.
- getJobs agora conta o total ANTES de aplicar o range e "grampeia" a
  página pedida ao intervalo válido [1, totalPages], evitando o offset
  inválido. Com 0 resultados, retorna a lista vazia sem nem tentar o range.
- JobsPage passou a usar o "page" devolvido por getJobs (já grampeado)
  para o componente Pagination, em vez do page cru da URL — senão
  ?page=999 mostrava "Página 999 de 1".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Alunos do workshop podem abrir o projeto direto do GitHub, sem instalar
Node/Docker localmente:

- .devcontainer/devcontainer.json: combina o docker-compose.yml da raiz
  (serviço postgres, pgvector) com docker-compose.extend.yml (serviço app,
  onde o VS Code roda) — é esse arquivo que o GitHub detecta pra habilitar
  "Create codespace on this branch". Node 22, extensões de ESLint/
  Prettier/Tailwind já pré-instaladas, porta 3000 com auto-preview.
- .devcontainer/Dockerfile: base oficial javascript-node:22 + psql client
  (pra inspecionar o Postgres local direto do terminal do Codespace).
- .devcontainer/docker-compose.extend.yml: sobe o serviço "app" ao lado do
  "postgres" já existente, ligados na mesma rede do compose.
- .devcontainer/post-create.sh: roda no primeiro boot — npm install, cria
  .env.local a partir do .env.example se não existir, e tenta aplicar as
  migrations + seed no Postgres local (best effort, não trava o Codespace
  se falhar).
- README.md: badge "Open in GitHub Codespaces" com nota de como abrir
  nesta branch enquanto o .devcontainer ainda não estiver em main.

Validado localmente antes de commitar: buildei a imagem, subi app+postgres
via `docker compose -f docker-compose.yml -f .devcontainer/docker-compose.extend.yml up`,
confirmei a rede compartilhada (app resolve "postgres" por nome), o bind
mount correto do repo e o post-create.sh de ponta a ponta dentro do
container (npm install, .env.local, migrations via psql). Corrigi no
caminho um bug real: paths relativos ("..") em docker-compose.extend.yml
resolviam para um nível ACIMA da raiz do repo quando combinados com -f —
o Compose usa o diretório do primeiro arquivo (-f) como base, não o do
arquivo que declara o caminho. Ambiente de teste (containers, volume e
imagem) já foi limpo depois da validação.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dois problemas apontados pelo CI (run 35765942240, job 106875379622):

- app/(dashboard)/jobs/[id]/page.tsx: erro FATAL de build. Next.js 15
  exige que `params` de rota dinâmica seja Promise<{...}>, mas o tipo
  ainda estava como objeto plano ({ id: string }) — o `next build`
  falhava em "Linting and checking validity of types". Corrigido pra
  `params: Promise<{ id: string }>` + `const { id } = await params`.
- app/(auth)/login/page.tsx: warning do react-hooks/exhaustive-deps
  (doRedirect fora do array de dependências do useEffect). doRedirect
  agora é useCallback([redirectTo]) e entra na dependência do efeito;
  removido o `router` que estava no array sem ser usado dentro da função.

Validado localmente reproduzindo os 3 passos do job "quality": npm run
lint (0 warnings), npm run type-check (0 erros) e npm run build (verde,
15 rotas geradas, incluindo /jobs/[id] e /login).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…testando)

Corrigir o params/Promise não foi suficiente — reproduzi localmente as
condições exatas do runner (sem .env.local, só env vars) e o `next build`
falha de novo, mais adiante, no "Collecting page data":

1. lib/supabase.ts cria o client no carregamento do módulo; sem
   NEXT_PUBLIC_SUPABASE_URL/ANON_KEY, createClient lança "supabaseUrl is
   required" ao processar /jobs/[id].
2. Depois de contornar isso, lib/firebase-admin.ts falha do mesmo jeito em
   /api/auth/session: sem FIREBASE_PROJECT_ID/CLIENT_EMAIL/PRIVATE_KEY,
   o Admin SDK nem inicializa.
3. E uma FIREBASE_PRIVATE_KEY qualquer não resolve: cert() do
   firebase-admin valida o PEM via OpenSSL na hora, então precisa ser uma
   chave RSA sintaticamente válida — não pode ser um texto arbitrário.

Nenhuma dessas chamadas faz request de rede real durante o build (é só
inicialização de cliente), então não precisa ser segredo de verdade — só
sintaticamente válido. O step "Build" agora define as NEXT_PUBLIC_*/
FIREBASE_* como valores fake fixos, e gera uma chave RSA descartável com
openssl NA HORA (não fixa no arquivo, pra não parecer segredo comitado e
não disparar secret scanning).

Validado batendo o cenário exato do CI: sem .env.local, só essas env vars,
rodando o mesmo `bash -eo pipefail` que o GitHub Actions usa — build verde,
15 rotas geradas, exit 0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dannyserena
dannyserena merged commit 755cce7 into main Sep 22, 2026
1 check passed
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.

1 participant