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