Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Imagem oficial de dev containers da Microsoft já traz Node 22, npm, git,
# zsh/oh-my-zsh e o usuário não-root "node" configurado — evita reinventar
# esse setup só para o workshop.
FROM mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm

# postgresql-client: dá aos alunos um `psql` pronto no terminal do Codespace
# para inspecionar o Postgres local (pgvector) definido no
# docker-compose.yml da raiz, sem precisar instalar nada na hora.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends postgresql-client \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*

USER node
48 changes: 48 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "GDG Jobs — Workshop",
// Carrega o docker-compose.yml da raiz (serviço "postgres", pgvector) +
// o extend.yml deste diretório (serviço "app", onde o VS Code roda).
// É esse arquivo que o GitHub detecta para habilitar Codespaces no repo.
"dockerComposeFile": ["../docker-compose.yml", "docker-compose.extend.yml"],
"service": "app",
"workspaceFolder": "/workspaces/gdgjobs",
"shutdownAction": "stopCompose",

"forwardPorts": [3000, 5432],
"portsAttributes": {
"3000": {
"label": "GDG Jobs (Next.js)",
"onAutoForward": "openPreview"
},
"5432": {
"label": "Postgres (pgvector)",
"onAutoForward": "silent"
}
},

"postCreateCommand": "bash .devcontainer/post-create.sh",

"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"editorconfig.editorconfig",
"ms-azuretools.vscode-docker"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"tailwindCSS.includeLanguages": {
"plaintext": "html"
}
}
}
},

"remoteUser": "node"
}
25 changes: 25 additions & 0 deletions .devcontainer/docker-compose.extend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Serviço extra para o Codespace/Dev Container. Não substitui o
# docker-compose.yml da raiz — devcontainer.json carrega os dois juntos,
# então o serviço "postgres" (pgvector) já definido lá continua sendo a
# mesma fonte usada em desenvolvimento local fora do Codespace.
services:
app:
build:
# Ao combinar múltiplos -f, o Compose resolve caminhos relativos com
# base no diretório do PRIMEIRO arquivo (docker-compose.yml da raiz),
# não no diretório deste próprio arquivo — por isso "." aqui já é a
# raiz do repo, não .devcontainer/.
context: .
dockerfile: .devcontainer/Dockerfile
volumes:
# Bind mount do repo inteiro (mesma ressalva do context acima: "."
# já é a raiz do repo aqui) — editar no VS Code do Codespace edita o
# mesmo arquivo que roda dentro do container.
- .:/workspaces/gdgjobs:cached
command: sleep infinity
depends_on:
- postgres
environment:
# Dentro da rede do compose, o Postgres é alcançado pelo nome do
# serviço ("postgres"), não por localhost.
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/postgres
49 changes: 49 additions & 0 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Roda uma vez, quando o Codespace/Dev Container é criado. Espelha o
# scripts/setup.sh usado em dev local, mas sem exigir Docker Desktop na
# máquina do aluno — aqui o Postgres já é outro serviço do compose.
set -uo pipefail

echo "==> Instalando dependências (npm install)"
npm install

if [ ! -f .env.local ]; then
cp .env.example .env.local
echo "==> .env.local criado a partir de .env.example"
echo " Preencha as chaves de Firebase/Supabase/Gemini antes de testar"
echo " login, banco real ou busca por IA — veja docs/onboarding/."
else
echo "==> .env.local já existe; mantendo configuração atual."
fi

echo "==> Aguardando o Postgres local (pgvector) ficar pronto..."
for _ in $(seq 1 20); do
if pg_isready -h postgres -p 5432 -U postgres >/dev/null 2>&1; then
break
fi
sleep 2
done

if pg_isready -h postgres -p 5432 -U postgres >/dev/null 2>&1; then
echo "==> Aplicando migrations no Postgres local (dados de exemplo, não é o Supabase real)"
for f in packages/database/migrations/*.sql; do
echo " - $f"
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f "$f" || echo " (aviso: falhou, pode já ter sido aplicada)"
done
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f packages/database/seeds/jobs.sql \
|| echo " (aviso: seed falhou, talvez já tenha rodado antes)"
else
echo "==> Postgres local não respondeu a tempo. Depois, rode manualmente:"
echo " psql \"\$DATABASE_URL\" -f packages/database/migrations/001_create_jobs_table.sql"
echo " psql \"\$DATABASE_URL\" -f packages/database/migrations/002_create_core_tables.sql"
fi

cat <<'EOF'

==============================================================
Ambiente do Codespace pronto!
1. Preencha .env.local com as chaves do workshop (Firebase/Supabase/Gemini)
2. npm run dev
3. Porta 3000 abre automaticamente em uma aba do navegador
==============================================================
EOF
105 changes: 61 additions & 44 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,46 +1,63 @@
# ====== App ======
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_NAME=GDG Jobs
NEXT_PUBLIC_ENVIRONMENT=development

# ====== Supabase ======
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
SUPABASE_JWT_SECRET=your-jwt-secret
SUPABASE_DB_URL=postgresql://postgres:postgres@localhost:5432/postgres

# ====== Firebase Auth ======
NEXT_PUBLIC_FIREBASE_API_KEY=your-firebase-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
# ============================================================
# GDG Jobs — Variáveis de Ambiente
# Copie este arquivo para .env.local e preencha com seus dados
# NUNCA commit .env.local! Já está no .gitignore
# ============================================================

# ─────────────────────────────────────────────────────────────
# FIREBASE AUTH (Client-side — prefixo NEXT_PUBLIC_)
# Pegue em: Firebase Console → Project Settings → Geral
# ─────────────────────────────────────────────────────────────

NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=seu-projeto.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=seu-projeto
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=seu-projeto.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789012
NEXT_PUBLIC_FIREBASE_APP_ID=1:123456789012:web:abcdef1234567890
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=G-XXXXXXXXXX
FIREBASE_CLIENT_EMAIL=service-account@project.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"

# ====== AI / Gemini ======
GEMINI_API_KEY=your-gemini-api-key
GEMINI_MODEL=gemini-1.5-flash

# ====== Email ======
RESEND_API_KEY=your-resend-api-key
EMAIL_FROM=no-reply@localhost

# ====== Vercel / Deploy ======
VERCEL_ENV=development
VERCEL_URL=http://localhost:3000

# ====== Observability ======
SENTRY_DSN=
LOG_LEVEL=info

# ====== External services ======
LINKEDIN_API_KEY=
GITHUB_TOKEN=

# ====== Security ======
NEXTAUTH_SECRET=replace-me
SESSION_SECRET=replace-me
# ─────────────────────────────────────────────────────────────
# FIREBASE ADMIN (Server-side only — SEM prefixo NEXT_PUBLIC)
# Necessário para emitir o cookie __session que o middleware usa
# para proteger /dashboard, /profile, /submit-job.
# Gere em: Firebase Console → Project Settings → Contas de serviço
# → Gerar nova chave privada (baixa um JSON)
# ⚠️ NUNCA exponha estas credenciais no frontend!
# ─────────────────────────────────────────────────────────────

FIREBASE_PROJECT_ID=seu-projeto
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@seu-projeto.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n"

# ─────────────────────────────────────────────────────────────
# SUPABASE (Client-side — prefixo NEXT_PUBLIC_)
# Pegue em: Supabase Dashboard → Project Settings → API
# ─────────────────────────────────────────────────────────────

NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxxxxxxxxxxxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...anon-key-publica

# ─────────────────────────────────────────────────────────────
# SUPABASE (Server-side only — SEM prefixo NEXT_PUBLIC)
# ⚠️ NUNCA exponha esta chave no frontend!
# Pegue em: Supabase Dashboard → Project Settings → API → service role
# ─────────────────────────────────────────────────────────────

SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIs...service-role-secreta

# ─────────────────────────────────────────────────────────────
# GEMINI (Server-side only — busca de vagas em linguagem natural)
# Pegue em: https://aistudio.google.com/apikey
# ⚠️ NUNCA exponha esta chave no frontend!
# ─────────────────────────────────────────────────────────────

GEMINI_API_KEY=AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# GEMINI_MODEL=gemini-2.0-flash

# ─────────────────────────────────────────────────────────────
# RESEND (opcional — para alertas por e-mail na V2)
# Pegue em: https://resend.com → API Keys
# ─────────────────────────────────────────────────────────────

# RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
24 changes: 23 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,26 @@ jobs:
run: npm run type-check

- name: Build
run: npm run build
# O build executa (não só compila) o código server-side pra coletar
# dados de cada rota — lib/supabase.ts e lib/firebase-admin.ts
# inicializam seus clientes no carregamento do módulo, então
# falham se as env vars estiverem ausentes, mesmo sem nenhuma
# chamada de rede real acontecer. Não há segredo de verdade aqui:
# são valores fake só pra passar da inicialização; a "chave
# privada" do Firebase Admin é gerada na hora (não pode ser um
# texto fixo: cert() do firebase-admin valida o PEM via OpenSSL
# antes mesmo de qualquer request).
env:
NEXT_PUBLIC_SUPABASE_URL: https://placeholder.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY: placeholder-anon-key
NEXT_PUBLIC_FIREBASE_API_KEY: placeholder-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: placeholder.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID: placeholder-project
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET: placeholder.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: '000000000000'
NEXT_PUBLIC_FIREBASE_APP_ID: '1:000000000000:web:0000000000000000000000'
FIREBASE_PROJECT_ID: placeholder-project
FIREBASE_CLIENT_EMAIL: firebase-adminsdk-ci@placeholder-project.iam.gserviceaccount.com
run: |
export FIREBASE_PRIVATE_KEY="$(openssl genrsa 2048 2>/dev/null | awk 'BEGIN{ORS="\\n"}{print}')"
npm run build
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ GDG Jobs é o hub de vagas curado pela comunidade GDG para a comunidade de tecno
![Firebase](https://img.shields.io/badge/Firebase-Auth-FFCA28)
![Gemini](https://img.shields.io/badge/Gemini-AI-8B5CF6)

[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/lfdev-gdg/GDGJobs)

> Enquanto o `.devcontainer/` ainda não estiver em `main`, use **Code →
> Codespaces → "..." → New with options** e selecione a branch atual em vez
> do botão acima.

## Visão geral

Este repositório organiza a estrutura inicial do produto, com foco em:
Expand Down
Loading
Loading