DeepSeek Harness Remote
DeepSeek Harness Remote 可将手机或另一台电脑与你运行 DeepSeek Harness 的电脑安全连接,随时随地继续你的工作,方便随时查看进度并继续工作。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Rastreador de candidaturas: Kanban, métricas, automação por e-mail, resumo diário e caça-vagas (Next.js + Supabase)
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Sistema web para acompanhar candidaturas a vagas (estágio, trainee, CLT, PJ, temporário ou freela), do "quero me candidatar" até a proposta. Tem quadro Kanban com arrastar e soltar, linha do tempo de cada vaga, próximos passos com prazo e um painel com o funil e a taxa de resposta. Também acompanha concursos públicos: cronograma, contagem até a prova, matérias, leitor de edital e busca diária de editais abertos.
Demonstração: rastreador-de-candidaturas.vercel.app. Clique em Explorar a demonstração: a conta já vem com dados de exemplo, e eles voltam ao original todo dia.
Procurar estágio ou emprego vira uma planilha bagunçada rápido: vagas em várias plataformas, testes online com prazo, entrevistas em etapas diferentes e nenhuma noção de onde o processo costuma travar. Este projeto resolve isso para uso diário e, ao mesmo tempo, serve de vitrine técnica: CRUD completo com back-end, banco relacional com regras de segurança por usuário, login, testes e deploy.
N nova candidatura, / buscar, Ctrl+K paleta de comandos, G e
depois P/Q/L/C/V/O para navegar, ? mostra todos os atalhos.| Quadro | Detalhe |
|---|---|
| Lista | Modo escuro |
| Caixa de entrada | Celular |
| Vagas sugeridas | |
| Camada | Escolha |
|---|---|
| Framework | Next.js 16 (App Router, Server Components, Server Actions, Cache Components) com TypeScript |
| Interface | Tailwind CSS v4, shadcn/ui (Radix), lucide-react, Sonner (toasts), next-themes |
| Banco e login | Supabase: PostgreSQL, Auth e Row Level Security, via @supabase/ssr |
| Formulários | React Hook Form + Zod (o mesmo schema valida no navegador e no servidor) |
| Arrastar e soltar | dnd-kit (mouse, toque e teclado, com anúncios para leitores de tela) |
| Gráficos | Recharts (pelos componentes de gráfico do shadcn) e barras em HTML/CSS |
| Testes | Vitest |
| Deploy | Vercel (com Cron diário para a conta demo) |
auth.users ──┬──< applications ──┬──< stage_history (preenchida por trigger)
│ ├──< tasks
│ └──< inbox_items (sugestões da caixa de entrada)
├── user_settings (token do e-mail e automação)
├── job_profiles (perfil do caça-vagas)
├──< job_leads (vagas sugeridas, com nota)
├── resumes (o que foi lido do currículo)
├──< concursos ──┬──< concurso_stage_history (preenchida por trigger)
│ ├──< concurso_dates (cronograma)
│ ├──< concurso_subjects (matérias)
│ └──< tasks (a mesma tabela das candidaturas)
├── concurso_profiles (perfil do caça-concursos)
├──< concurso_leads >── concurso_notices (sugestões; o catálogo é compartilhado)
└── (user_id em todas as tabelas, para o RLS)
CHECK exige exatamente um dos dois). Assim o painel lê todos os prazos de um lugar só.As etapas são fixas e definidas em um só lugar (src/lib/stages.ts): nome, cor,
ordem no funil e tipo. As mesmas chaves estão travadas no banco por restrições CHECK. As etapas
dos concursos ficam em src/lib/concurso-stages.ts, do mesmo jeito.
(select auth.uid()) = user_id). Tarefas e histórico ainda conferem se a candidatura ligada é
do mesmo usuário.getClaims() (confere a assinatura do token) e toda Server
Action revalida a entrada com Zod, mesmo que o navegador já tenha validado.NEXT_PUBLIC_.auth.users recusa
trocar o e-mail dela e só aceita trocar a senha para a senha oficial, guardada criptografada no
Vault do Supabase. Assim, nem chamando supabase.auth.updateUser() direto pelo navegador um
visitante consegue tomar a conta. O Supabase não tem um Auth Hook que rode antes de alterar um
usuário, por isso a regra fica no banco. O cron de reset continua funcionando porque registra a
senha oficial (função protect_demo_account, só para a chave secreta) antes de redefini-la.<user_id>/curriculo.pdf). O servidor confere a assinatura do arquivo (%PDF-), não só o tipo
informado pelo navegador, e o PDF só abre por um link temporário de 1 minuto. Na conta demo,
enviar e apagar currículo é recusado pelas próprias regras do banco e do Storage (uma função em
private, fora da API, diz se a conta é protegida), porque a conta é compartilhada.=, +, -, @ no início de um campo).http(s), recusa endereços internos (inclusive depois de redirecionar, porque confere o IP na
hora de conectar), segue no máximo 3 redirecionamentos e para em 10 MB ou 20 segundos.inbox_ingest) que só aceita um token pessoal:
o banco guarda apenas o hash (SHA-256) dele e grava só na conta dona do token. O Supabase avisa
que essa função pode ser chamada sem login. Isso é intencional: quem chama é o script do Google,
que não tem sessão, e sem um token válido a função recusa a chamada.As métricas usam a etapa mais avançada que cada vaga alcançou, a partir do histórico. Uma vaga reprovada depois da entrevista com RH continua contando como "chegou à entrevista com RH". E uma vaga que pulou o teste online conta como tendo passado por ele.
A lógica fica em src/features/dashboard/metrics.ts e tem testes.
Cada card tem uma position decimal. Ao soltar um card entre dois outros, ele recebe a média das
posições vizinhas, então só o card movido é salvo no banco. A interface atualiza antes da
resposta do servidor e volta ao estado anterior se algo der errado.
src/
app/ Rotas (App Router)
(auth)/ login, cadastro, recuperar e redefinir senha
(app)/ painel, quadro, lista, caixa-de-entrada, vagas, conexoes, candidaturas/[id], nova, editar
(app)/concursos/ lista, quadro, sugeridos, perfil, ler-edital, novo, [id], [id]/editar
api/export/ download do CSV (candidaturas e /concursos)
api/concursos/ edital (leitor), buscar ("Buscar agora") e agenda (.ics)
api/cron/concursos/ busca diária de concursos (DOU e Querido Diário)
api/cron/reset-demo/ restauração diária da conta demo
api/cron/vagas/ busca diária de vagas para todos os perfis
api/vagas/buscar/ busca de quem está logado (ao abrir o app e no botão "Buscar agora")
api/inbox/email/ recebe os e-mails enviados pelo script do Google
api/report/ resumo diário (chamado pelo script do Google)
api/whatsapp/webhook/ assistente do WhatsApp (API oficial da Meta)
auth/callback/ retorno dos e-mails e do Google
features/ Código organizado por funcionalidade
applications/ schema (Zod), actions, queries, filtros, CSV, componentes
board/ lógica do Kanban (pura e testada) e componentes
dashboard/ cálculo das métricas e gráficos
tasks/ próximos passos
auth/ sessão, actions e formulários de login
demo/ dados de exemplo e conta demo
inbox/ leitor de mensagens (regras), plano de cada sugestão, script do Google
report/ montagem do resumo diário (e-mail, WhatsApp e prévia)
whatsapp/ assistente: comandos, vinculação por código, webhook
job-search/ caça-vagas: fontes (Gupy, Greenhouse, Lever), nota, bolsa e benefícios, busca
resume/ currículo: leitura do PDF, habilidades, idiomas, curso, sugestões
concursos/ concursos: cronograma, matérias, leitor de edital, agenda, .ics, CSV
concursos/search/ caça-concursos: DOU, Querido Diário, catálogo, nota, perfil
components/ Componentes compartilhados (app-shell, ui do shadcn, etc.)
lib/ Supabase, etapas, opções, formatação pt-BR, CSV, erros
types/database.ts Tipos do banco
supabase/migrations/ SQL do banco (tabelas, trigger, RLS, índices)
scripts/seed-demo.ts Cria/recria a conta demo
tests/ Testes (Vitest)
assets/fonts/ Fonte Geist (licença OFL) usada na imagem de compartilhamento
assets/demo/ Currículo fictício da conta demo (também usado nos testes)
.github/workflows/ci.yml CI: lint, testes e build a cada push e pull request
Crie uma conta em supabase.com e clique em New project. Escolha a região South America (São Paulo) e guarde a senha do banco.
Crie as tabelas: no menu lateral, abra SQL Editor → New query. Cole o conteúdo de cada arquivo da pasta supabase/migrations e clique em Run, um por vez e nesta ordem:
20261019000000_init.sql20261019000100_stage_history_immutable.sql20261020000000_job_type_and_salary.sql20261020010000_inbox.sql20261020010100_inbox_ingest_anon_only.sql20261021000000_report_and_whatsapp.sql20261022000000_job_search.sql20261027000000_protect_demo_account.sql20261028000000_job_lead_details.sql20261028010000_resumes.sql (cria também o bucket curriculos do Storage)20261029000000_concursos.sql20261029010000_concurso_search.sql20261029020000_concurso_report.sqlConfira em Table Editor se apareceram applications, stage_history, tasks,
inbox_items, user_settings, job_profiles, job_leads, concursos, concurso_dates,
concurso_subjects, concurso_profiles, concurso_notices e concurso_leads, todas com o selo
de RLS ativado.
Se você usa a CLI do Supabase:
npx supabase link --project-ref <id>enpx supabase db push.
Copie as chaves para o .env.local (copie o .env.example primeiro):
http://localhost:3000 e https://SEU-APP.vercel.app.https://xxxx.supabase.co/auth/v1/callback)..env.local (e na Vercel), defina NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=true. O botão "Continuar
com Google" só aparece com essa variável ligada.SUPABASE_SECRET_KEY, DEMO_EMAIL e DEMO_PASSWORD no .env.local.
O e-mail não precisa existir (ex.: [email protected]): o script cria a conta pela API
administrativa, já confirmada. Só a tela de cadastro comum exige um domínio que receba e-mails;
o Supabase recusa até @example.com ali.npm run seed:demo. O script cria a conta (já confirmada) com 20 candidaturas de empresas
fictícias, histórico e tarefas, e as datas ficam relativas ao dia em que ele roda./api/cron/reset-demo todo dia às 3h (horário de Brasília)
e restaura dados e senha. Dentro da conta demo também há um botão Restaurar agora.exemplo, que a busca de verdade ignora, e todos os links são de
example.com.Qualquer outra conta pode carregar os mesmos dados de exemplo pelo botão Carregar dados de exemplo, que aparece quando a conta está vazia (na página de concursos, o botão carrega os concursos de exemplo).
O app não enxerga o que você faz no navegador nem no celular. Ele recebe sinais de três lugares, e todos viram sugestões na Caixa de entrada:
| De onde vem | Como chega | Configuração |
|---|---|---|
| E-mails (Gupy, LinkedIn, sites de vagas, recrutadores) | Um script do Google Apps Script, rodando na sua conta Google, confere o Gmail a cada 10 minutos e envia só os e-mails de processos seletivos | Uma vez, cerca de 2 minutos |
| Mensagens (WhatsApp, LinkedIn, qualquer texto) | Botão Colar mensagem | Nenhuma |
| Compartilhar no Android | Com o app instalado no celular, ele aparece no menu Compartilhar | Instalar o app pelo navegador |
O que o app entende (regras em português, sem IA e sem custo, em src/features/inbox/parser.ts):
Automático ou com confirmação: confirmações de inscrição e reprovações com frase clara são aplicadas sozinhas quando o app abre (dá para desligar na Caixa de entrada). O resto aparece como sugestão com uma prévia ("Nuvem Pay → Entrevista técnica · próximo passo até 23/10") e é aplicado com um clique. A etapa nunca anda para trás (um e-mail atrasado não tira a vaga da entrevista) e vagas já encerradas não mudam.
Conectar o Gmail: na Caixa de entrada, clique em Conectar e-mail e siga os passos. O app
gera um script com o seu token pessoal; você cola em script.google.com,
roda a função configurar uma vez e autoriza. O script precisa do endereço publicado (Vercel),
porque o Google não alcança o localhost do seu computador.
Custo zero para todo mundo: cada pessoa conecta o próprio e-mail, e o script roda na conta Google dela. Não há serviço pago no caminho. Um botão "Conectar com Google" de um clique exigiria que o Google auditasse o app (processo pago) para ler o Gmail de outras pessoas. O script evita isso.
O mesmo script do Google manda, todo dia no horário escolhido (padrão: 7h), um resumo para o Gmail da própria pessoa: prazos atrasados, de hoje e da semana; o que mudou desde ontem; sugestões esperando na caixa de entrada; vagas em andamento sem novidade há 14 dias ou mais; as vagas novas do caça-vagas; as datas dos concursos na semana (fim das inscrições, boleto, prova...) e os concursos novos sugeridos; e os números da semana. A prévia aparece na página Conexões. O envio usa a cota gratuita de e-mails da própria conta Google, então não custa nada.
Pela API oficial da Meta. Ele só responde quando a pessoa escreve, e por isso é grátis: a Meta não cobra até 1.000 respostas por mês por número (regra em vigor desde 1º/10/2026). Mensagens que a empresa inicia, como um relatório enviado sozinho todo dia, são cobradas. Por isso o resumo automático vai por e-mail e o WhatsApp funciona sob demanda.
O que a pessoa pode mandar: resumo, prazos, andamento, sugestões, vagas, concursos
(alertas de inscrição e boleto da semana, as próximas datas e os concursos novos), o nome de uma empresa
("como está a Nuvem Pay?") ou uma mensagem encaminhada de recrutador, que vira sugestão na caixa
de entrada. Para conectar, ela gera um código em Conexões e manda vincular CÓDIGO para o
assistente, o que prova que o número é dela. Mandar desvincular desconecta.
Como configurar (quem publica o app faz uma vez):
whatsapp_business_messaging. Para testar, adicione o
seu número na lista de destinatários: o número de teste só conversa com até 5 números cadastrados.https://SEU-APP.vercel.app/api/whatsapp/webhook,
invente um token de verificação (o mesmo de WHATSAPP_VERIFY_TOKEN) e assine o campo
messages.WHATSAPP_TOKEN, WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_APP_SECRET,
WHATSAPP_VERIFY_TOKEN, NEXT_PUBLIC_WHATSAPP_BOT_NUMBER (o número do assistente, com DDI e DDD)
e SUPABASE_SECRET_KEY. Faça um novo deploy.Sem WHATSAPP_TOKEN e WHATSAPP_PHONE_NUMBER_ID, o assistente fica em modo de teste: as
respostas aparecem no log e na resposta do webhook, sem envio pela Meta.
WhatsApp pessoal: não existe um meio oficial de um app ler as suas conversas, e as ferramentas não oficiais podem banir o número. Por isso as mensagens de recrutadores entram pelo Colar mensagem, pelo Compartilhar do Android ou encaminhadas para o assistente.
Na página Vagas sugeridas, a pessoa monta um perfil de busca uma vez: cargos (até 5), tipos de vaga, modelos de trabalho, cidade e estado, remuneração mínima, palavras-chave do currículo, palavras para evitar e as fontes. A partir daí o app busca vagas todo dia e mostra as mais compatíveis.
Fontes (todas públicas, sem login e sem custo):
| Fonte | Como o app lê | Observação |
|---|---|---|
| Gupy | A mesma busca pública que o portal de vagas da Gupy usa no navegador, por cargo, tipo de vaga, estado e vagas remotas | Não é uma API oficial: se a Gupy mudar o formato, a busca registra o erro e as outras fontes seguem funcionando |
| Greenhouse | Job Board API, a listagem pública oficial de cada empresa | Não tem busca geral, por isso existe uma lista pronta de 16 empresas com vagas no Brasil (QuintoAndar, Stone, C6 Bank, Inter, XP, BTG, VTEX, EBANX, Wellhub e outras) |
| Lever | Postings API, também oficial e pública | Lista pronta com CI&T, Neon, Swile e dLocal |
A pessoa pode acrescentar outras empresas colando o link da página de vagas
(boards.greenhouse.io/... ou jobs.lever.co/...). A lista pronta fica em
src/features/job-search/boards.ts. LinkedIn e Indeed ficam de
fora: não têm listagem pública e proíbem a coleta automática.
Nota de compatibilidade (regras em src/features/job-search/score.ts, sem IA): cargo 45 pontos, tipo de vaga 20, local e modelo 20, palavras-chave e habilidades do currículo 15. O cargo é comparado sem acentos e com sinônimos em português e inglês ("Dados" = "Data", "Desenvolvedor" = "Developer"). Cada ponto vira um motivo na tela. Ficam de fora, em vez de ganhar nota baixa: outro tipo de vaga, nível sênior ou de liderança (quando o cargo do perfil não pede), outra cidade em vaga presencial ou híbrida, vaga fora do Brasil, inscrições encerradas, banco de talentos, jovem aprendiz e títulos com palavras a evitar. Remuneração abaixo do mínimo vira aviso e desconta pontos. Só entram vagas com nota a partir de 60, no máximo 30 novas por busca.
Bolsa, horário e benefícios (regras em src/features/job-search/details.ts): nenhuma fonte informa isso de forma organizada, então o app lê a descrição da vaga. Pega o valor só perto de "bolsa", "salário" ou "remuneração" (e ignora "bolsa de estudos", "bolsa de valores", valor por hora e "R$ 10 milhões"), a jornada ("6h por dia", "30h por semana", "das 9h às 15h") e 20 benefícios comuns (vale-transporte, vale-refeição, plano de saúde, Wellhub/Gympass, auxílio home office, PLR, day off...). Os benefícios só são lidos a partir da parte de benefícios da vaga, para não confundir com a apresentação da empresa ("somos líderes em plano de saúde"). Na dúvida, a informação fica de fora. A Gupy já manda a descrição completa na busca. O Greenhouse não: a lista com todas as descrições pesa megabytes por empresa, então o app baixa a descrição (cerca de 17 KB) só das vagas que já passaram no filtro e refaz a nota com ela.
Quando roda:
/api/cron/vagas, às 5h de Brasília), para todos os
perfis com busca automática. Os downloads das páginas das empresas são reaproveitados entre os
perfis. Precisa da SUPABASE_SECRET_KEY.As vagas novas aparecem no menu (com o número), na página Vagas sugeridas, no resumo diário
por e-mail e no comando vagas do assistente do WhatsApp. Adicionar ao quadro cria a
candidatura em "Quero me candidatar" com empresa, cargo, link, local, modelo, tipo e a nota.
Descartar tira a vaga da lista para sempre (com desfazer).
No Perfil de busca, a pessoa envia o currículo em PDF (até 4 MB). O texto sai do PDF com a biblioteca unpdf (o pdf.js da Mozilla, sem dependências nativas) e é lido por regras, sem IA (src/features/resume/extract.ts):
Com isso, o app sugere cargos (do curso e das áreas com mais habilidades: "Estágio em Dados"), tipos de vaga (estágio para quem estuda; trainee para quem se forma em até um ano ou se formou há até dois) e a cidade. Nada muda sozinho: a pessoa marca o que quer, clica em Usar no perfil, confere e salva.
Nas buscas, as habilidades do currículo somam com as palavras-chave do perfil na nota e aparecem como motivo ("Do currículo: Pandas"). Quando a vaga pede inglês ou espanhol avançado e o currículo diz menos (ou não cita o idioma), a vaga ganha um aviso ("Inglês avançado: seu currículo diz intermediário"). Enviar, trocar ou apagar o currículo libera uma busca nova.
Privacidade: nome, e-mail, telefone, endereço e documentos não são lidos nem guardados. O PDF fica no bucket privado e pode ser apagado a qualquer momento, junto com o que foi lido dele. PDF escaneado (só imagem) não tem texto: o app avisa e pede para exportar de novo pelo Word ou pelo Google Docs.
Concurso não segue as etapas de uma vaga (não tem entrevista nem proposta), então tem um módulo
próprio, no menu Concursos (atalho G e depois O), com o mesmo padrão das candidaturas:
lista com filtros, quadro Kanban, página de detalhe, linha do tempo e próximos passos.
Etapas: Acompanhando · Edital publicado · Inscrição feita · Taxa paga · Prova marcada · Prova feita · Resultado · Aprovação · Nomeação · Sem aprovação · Desisti. Os nomes falam da etapa, não da pessoa ("Inscrição feita", e não "Inscrita").
Página do concurso: cronograma em linha do tempo (o que já passou fica apagado, inscrição e
boleto vencendo em 7 dias ficam em destaque), contagem até a prova, matérias com barra de
progresso pelo peso de cada uma, próximos passos, histórico, Ir para a inscrição (abre o site
oficial) e Adicionar à agenda, que baixa o cronograma em .ics com lembrete na véspera. No
celular, basta abrir o arquivo; no Google Agenda pelo computador, use Configurações → Importar e
exportar. Na lista, o menu ao lado de "Novo concurso" exporta os concursos em CSV e a agenda de
todos eles.
Leitor de edital (Ler edital): a pessoa cola o texto ou o link do edital (PDF, página do órgão ou do Diário Oficial) e o app preenche órgão, cargos, banca, esfera, escolaridade, salário, taxa, vagas, cadastro reserva, local, links e o cronograma. É por regras, sem IA e sem custo (src/features/concursos/notice-parser.ts), testado com trechos reais de editais do DOU. A pessoa confere tudo antes de salvar. Sites que só funcionam com JavaScript (como o do Cebraspe) não entregam o texto: o app avisa e pede o link do PDF.
No Perfil de concursos, a pessoa diz a escolaridade, as áreas e os cargos que interessam, as
esferas, as cidades (no formato Cidade/UF), os estados, o salário mínimo, as bancas preferidas e
se aceita mudar de cidade. O app procura editais de abertura e mostra os que combinam em
Concursos sugeridos, com nota, motivos e destaque para inscrições que terminam em até 7 dias.
Acompanhar cria o concurso com o cronograma já preenchido; Descartar tira a sugestão para
sempre.
Fontes:
| Fonte | Como o app lê | Cadastro |
|---|---|---|
| Diário Oficial da União, Seção 3 pelo INLABS | Baixa o ZIP de XML do dia e separa as matérias do tipo "Edital" que abrem concurso (extratos, homologações e retificações ficam de fora) | Precisa de conta, gratuita e pessoal: crie em inlabs.in.gov.br e preencha INLABS_EMAIL e INLABS_PASSWORD (veja o .env.example) |
| DOU pela página de Dados Abertos da Imprensa Nacional | O mesmo XML, num ZIP por mês (cerca de 60 MB), atualizado todo dia | Nenhum. É a reserva automática quando o INLABS não está configurado ou está fora do ar |
| Querido Diário (Open Knowledge Brasil) | API pública com os diários oficiais das prefeituras. O app busca "concurso público" e "edital" nas cidades dos perfis e aceita só trechos de edital de abertura (nomeações e licitações ficam de fora) | Nenhum |
Cobertura do Querido Diário em Minas Gerais (conferida em 27/10/2026): 55 cidades aparecem na lista, mas só 20 têm diários. Estão em dia Betim, Campo Belo, Candeias, Carmo da Cachoeira, Carmo do Rio Claro, Contagem, Crucilândia, Itajubá, Itaúna, Januária, Juatuba, Nova Serrana, Onça de Pitangui, Piranguinho, Salinas, Taiobeiras, Uberaba e Várzea da Palma. Belo Horizonte parou em 25/03/2026 e Uberlândia em 05/03/2026. Outras 35 (entre elas Juiz de Fora, Montes Claros, Ipatinga, Divinópolis e Sete Lagoas) estão listadas sem nenhum diário. A página do perfil mostra a situação de cada cidade da pessoa.
O que fica de fora, de propósito:
robots.txt liberar robôs não é autorização para usar os dados).Nota de compatibilidade (regras em src/features/concursos/search/score.ts, sem IA): cargo e área 40 pontos, escolaridade 20, local 20, salário 10, banca preferida 10. Ficam de fora, em vez de ganhar nota baixa: inscrições encerradas, esfera fora do perfil, escolaridade acima da pessoa e outra cidade ou estado para quem não aceita mudar. Salário abaixo do mínimo vira aviso. Só entram editais com nota a partir de 55, no máximo 30 novos por busca.
Quando roda:
/api/cron/concursos, às 6h de Brasília): lê o DOU uma
vez, consulta o Querido Diário nas cidades de todos os perfis, grava no catálogo e dá a nota para
cada perfil. Precisa da SUPABASE_SECRET_KEY, porque só o cron grava no catálogo.No resto do app: a agenda dos concursos aparece no painel (alertas de inscrição, isenção e
boleto vencendo em 7 dias, e as próximas datas), as tarefas dos concursos entram em Próximos
prazos, e o resumo diário e o comando concursos do WhatsApp trazem os prazos da semana e os
concursos novos. O link Quais órgãos federais mais abrem vagas? leva ao
Radar de carreira, outro projeto com dados
públicos.
Requisitos: Node.js 20.9 ou mais novo e um projeto no Supabase (seção acima).
npm install
cp .env.example .env.local # e preencha as chaves
npm run dev # http://localhost:3000
| Comando | O que faz |
|---|---|
npm run dev | Servidor de desenvolvimento |
npm run build / npm start | Build e servidor de produção |
npm test | Roda os testes (Vitest) |
npm run lint | ESLint |
npm run typecheck | Checagem de tipos do TypeScript |
npm run seed:demo | Cria ou recria a conta de demonstração |
Os testes cobrem as partes que mais importam:
createApplication (grava para o usuário certo, não toca no banco com dados
inválidos, traduz erros do banco).moveApplication (filtra pelo dono, recusa etapa inválida,
posição padrão no topo), a edição pelo formulário e a lógica do Kanban (mover, reordenar, desfazer)./api/report e /api/whatsapp/webhook./api/curriculo (grava na pasta da pessoa, recusa arquivo que não é PDF e a
conta demo).ensureDemoUser e a rota /api/cron/reset-demo) registra a
senha oficial antes de redefini-la, nasce protegida quando é criada, não segue adiante se a
proteção falhar e recoloca o currículo fictício. Com SUPABASE_INTEGRATION=1 npm test, um teste extra entra na demo de verdade
com a chave pública, como um visitante, e confere que updateUser não troca senha nem e-mail.O CI roda npm ci, lint, testes e build a cada push e pull request,
com variáveis de ambiente falsas (o build não acessa o Supabase).
.env.local:
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY (obrigatórias)NEXT_PUBLIC_SITE_URL = https://SEU-APP.vercel.appSUPABASE_SECRET_KEY (conta demo, assistente do WhatsApp, busca diária de vagas e catálogo de concursos)INLABS_EMAIL, INLABS_PASSWORD (opcionais: o DOU pelo INLABS no caça-concursos)DEMO_EMAIL, DEMO_PASSWORD (conta demo)CRON_SECRET: um valor aleatório longo (por exemplo, gerado com openssl rand -hex 32)NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=true (se configurou o Google)WHATSAPP_* e NEXT_PUBLIC_WHATSAPP_BOT_NUMBER (se for usar o assistente do WhatsApp)https://SEU-APP.vercel.app/auth/callback nas Redirect
URLs. Se usa Google, adicione o domínio também nas origens autorizadas do Google Cloud.CRON_SECRET está definido, a Vercel envia esse valor no
cabeçalho e as rotas aceitam a chamada. O plano grátis da Vercel permite crons uma vez por dia.
O mesmo arquivo coloca o servidor em São Paulo (gru1), perto do banco do Supabase: se o seu
projeto do Supabase estiver em outra região, troque por uma próxima dele.SUPABASE_SECRET_KEY configurada) e o script do Gmail mantêm o banco ativo. Se pausar,
reative em Project → Restore no painel do Supabase.Variáveis
NEXT_PUBLIC_são embutidas no build. Se mudar alguma depois, faça um novo deploy (Deployments → ⋯ → Redeploy).
stages por usuário com uma "categoria" que
as métricas continuariam usando.application_id ou concurso_id.extractResume), fácil de trocar.MIT. A fonte Geist, em assets/fonts, é distribuída pela Vercel sob a SIL Open Font License.
| Variável | Onde encontrar no painel do Supabase |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Project Settings → Data API → Project URL (ou o botão Connect no topo) |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Project Settings → API Keys → Publishable key (começa com sb_publishable_) |
SUPABASE_SECRET_KEY | Project Settings → API Keys → Secret keys (começa com sb_secret_). Só é necessária para a conta demo, para o assistente do WhatsApp, para a busca diária de vagas pelo cron e para o catálogo do caça-concursos |
Configure os endereços de retorno: em Authentication → URL Configuration:
http://localhost:3000 (troque pelo endereço da Vercel depois do deploy).http://localhost:3000/auth/callback e, depois do deploy,
https://SEU-APP.vercel.app/auth/callback.Confirmação de e-mail: em Authentication → Sign In / Providers → Email, a opção Confirm email vem ligada. O servidor de e-mail gratuito do Supabase é só para testes: ele envia poucas mensagens por hora e apenas para e-mails da equipe do projeto. Escolha uma opção:
.ics