Skip to content
ceara-devPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Vagas (nome provisório)

Agregador de vagas inspirado no Glassdoor Brasil: API em Node.js com Clean Architecture e app Flutter com Clean Architecture e go_router.

Pasta O que é
glassdoor-api/ API (Node 24, TypeScript, Express 5, Prisma, PostgreSQL)
app_glassdoor/ App (Flutter 3.47.5 via FVM, flutter_bloc, go_router, dio)
globot/ Coletor de vagas de fontes oficiais (Greenhouse, Lever, Adzuna) que envia à API

Pré-requisitos

  • nvm (o Node vem do glassdoor-api/.nvmrc)
  • FVM (o Flutter vem do app_glassdoor/.fvmrc)
  • Docker com Compose. Seu usuário precisa estar no grupo docker: sudo usermod -aG docker $USER e depois sair e entrar na sessão.

Como rodar

# 1. Banco e Redis
docker compose up -d db db-test redis

# 2. API (http://localhost:3333)
cd glassdoor-api
nvm use
npm install                    # também gera o client do Prisma
cp -n .env.example .env        # só na 1ª vez (-n não sobrescreve); preencha JWT_ACCESS_SECRET e INGEST_API_TOKEN
npm run db:deploy              # aplica as migrations
npm run db:seed                # 200 vagas fictícias (apaga também as vagas ingeridas)
npm run dev

# 3. Worker de ingestão (outro terminal): coleta a Remotive na partida e depois a cada 6 h
cd glassdoor-api
npm run dev:worker

# 4. globot (opcional): vagas de páginas de carreira (Greenhouse, Lever) enviadas à API.
#    Precisa da API rodando, com INGEST_API_TOKEN no glassdoor-api/.env.
cd globot
nvm use && npm install
cp -n .env.example .env        # só na 1ª vez; copie para cá o INGEST_API_TOKEN do glassdoor-api/.env
npm run collect                # uma rodada (npm run dev: a cada 6 h)

# 5. App (outro terminal)
cd app_glassdoor
fvm flutter pub get
fvm dart run build_runner build --delete-conflicting-outputs
fvm flutter run --dart-define-from-file=env/dev.json     # emulador Android
fvm flutter run --dart-define-from-file=env/local.json   # Linux, macOS ou simulador iOS

# Celular Android pelo cabo USB: o localhost:3333 do celular passa a ser o da máquina
adb reverse tcp:3333 tcp:3333
fvm flutter run -d <id do celular> --dart-define-from-file=env/local.json

# Celular no mesmo Wi-Fi do PC (sem cabo): põe no app_glassdoor/.env o domínio do IP atual do PC
(cd glassdoor-api && npm run lan:app-env)    # ex.: http://api.192-168-0-135.sslip.io:3333/api/v1
fvm flutter run -d <id do celular> --dart-define-from-file=.env

app_glassdoor/.env: é a configuração local do app, fora do git, como o .env da API.

  • Criar: na primeira vez, cp -n .env.example .env. O modelo lista o API_BASE_URL de cada aparelho.
  • Uso: o app lê o .env sozinho ao iniciar, então basta fvm flutter run. Depois de editar o arquivo, faça hot restart (R).
  • Atalhos: um --dart-define-from-file (ex.: env/dev.json no emulador) tem prioridade sobre o .env. Esse valor fica fixo até o próximo flutter run, mesmo que a flag aponte para o próprio .env (como nas configurações do VS Code). Depois de editar o arquivo, pare (q) e rode de novo, porque o R não basta.
  • Gerar o endereço: o lan:app-env troca só a linha API_BASE_URL.
  • Segurança: o .env vai dentro do APK, então nada de segredo nele.

Domínio próprio na rede: api.glassdoor.lan

Um DNS no PC (dnsmasq, no compose) responde api.glassdoor.lan com o IP do PC e repassa os outros nomes à internet.

(cd glassdoor-api && npm run lan:app-env -- --dns)   # grava LAN_IP no .env da raiz e o domínio no app_glassdoor/.env
sudo docker compose --profile dns up -d --build      # sobe o DNS na porta 53 do IP do PC
dig @192.168.0.135 api.glassdoor.lan +short          # teste no PC: deve responder o IP do PC

No celular (Android 10 / MIUI 12):

  1. Abra Configurações → Wi-Fi e toque na seta da rede conectada.

  2. Em "Configurações de IP", troque para Estático e preencha:

    • Endereço IP: o atual do celular (ex.: 192.168.0.86);
    • Gateway: 192.168.0.1;
    • Prefixo: 24;
    • DNS 1: o IP do PC (192.168.0.135);
    • DNS 2: em branco. Com um DNS público ali, o Android às vezes pergunta a ele e não acha o nome.
  3. No navegador do celular, teste http://api.glassdoor.lan:3333/health. Com o celular no adb, confira também pelo PC:

    adb shell dumpsys connectivity | grep -o 'DnsAddresses: [^]]*]'   # deve listar só o IP do PC
    adb shell ping -c1 api.glassdoor.lan                              # deve responder do IP do PC

Se o DnsAddresses ainda listar endereços IPv6 depois do passo 2 (ex.: 2804:14d:1:0:181:213:132:2), eles são os DNS que o roteador da operadora anuncia por IPv6. O modo Estático não os remove. O Android pode perguntar a eles e não achar o nome, como acontece com um DNS 2 preenchido. Para resolver, desligue o IPv6 da rede local no roteador ou use o sslip.io (abaixo).

Enquanto o celular estiver com esse DNS, o PC e o container dns precisam estar ligados, senão os sites deixam de abrir nesse Wi-Fi. Para desfazer, volte a "Configurações de IP" para DHCP. Se o IP do PC mudar, rode o lan:app-env -- --dns de novo, depois sudo docker compose --profile dns up -d --force-recreate, e troque o DNS 1 no celular.

Por que .lan e não .local: iPhone, Mac, Linux e Android 12+ tratam .local como mDNS e nem perguntam ao DNS. O Android 10 não resolve .local de jeito nenhum.

Domínio sem configurar nada: o sslip.io é um DNS público que devolve o IP escrito no nome (api.192-168-0-135.sslip.io → 192.168.0.135). Ele funciona em qualquer celular, ao contrário de nomes .local, que o Android só resolve a partir da versão 12. O IP do PC vem por DHCP e pode mudar: rode o lan:app-env de novo, ou reserve o IP no roteador. Se o roteador bloquear o domínio, o comando avisa e usa o IP. Para gerar com o IP, use npm run lan:app-env -- --ip.

DioException [connection timeout]? O app está tentando um endereço que o aparelho não alcança. Sem --dart-define-from-file, o app usa 10.0.2.2, que só existe no emulador Android. Num celular físico, use o adb reverse acima. Confira também se a API responde: curl localhost:3333/health.

DioException [connection error]: Failed host lookup? O celular não achou o nome da API no DNS. O app mostra "Sem conexão. Verifique sua internet.", a mesma mensagem dos timeouts, mesmo com o celular conectado à internet. Com api.glassdoor.lan, a causa quase sempre é o celular ainda usar o DNS do roteador, e não o do PC. Confira nesta ordem:

curl localhost:3333/health                                        # 1. PC: a API responde?
dig @192.168.0.135 api.glassdoor.lan +short                       # 2. PC: o DNS devolve o IP do PC?
adb shell curl -s http://192.168.0.135:3333/health                # 3. celular: alcança a API pelo IP?
adb shell dumpsys connectivity | grep -o 'DnsAddresses: [^]]*]'   # 4. celular: qual DNS está usando?
adb shell ping -c1 api.glassdoor.lan                              # 5. celular: acha o nome?
  • 1 a 3 passam, mas o 5 dá unknown host: o problema é o DNS do celular. Faça os passos de "No celular" acima, ou use o sslip.io, que não depende dele: (cd glassdoor-api && npm run lan:app-env).
  • Falha no 1 ou no 2: suba a API ou o container dns.
  • Falha no 3: o celular e o PC não estão na mesma rede, ou um firewall bloqueia a porta 3333.

No VS Code, .vscode/launch.json tem uma configuração por alvo. A do celular USB já roda o adb reverse.

Alternativa: API, worker e globot em Docker

Sem Node na máquina e sem recarga automática: é o jeito "como em produção". Os segredos vêm dos mesmos .env (glassdoor-api/.env e globot/.env), e as migrations rodam sozinhas antes da API.

# Pare antes o npm run dev e o npm run dev:worker: usam a mesma porta e a mesma fila
docker compose --profile api up -d --build                   # bancos, Redis, migrations, API e worker
docker compose --profile api --profile globot up -d --build  # + globot (coleta a cada 6 h)

docker compose --profile api run --rm api-migrate npx prisma db seed   # vagas fictícias (apaga as vagas!)
docker compose logs -f api worker globot                                # acompanhar
docker compose --profile api --profile globot down                      # parar tudo (os dados ficam)

Sem estar no grupo docker, use sudo docker compose …. O app continua rodando na máquina, com fvm flutter run como acima.

Verificações

# API
cd glassdoor-api && npm run lint && npm run typecheck && npm test   # unit + integração (db-test)

# globot (sem rede: fontes em fixtures)
cd globot && npm run lint && npm run typecheck && npm test

# App
cd app_glassdoor && fvm flutter analyze && bash tool/check_layers.sh && fvm flutter test
# Ponta a ponta, com a API rodando:
fvm flutter test integration_test -d linux --dart-define-from-file=env/local.json

Estado

Concluídas:

  • Fase 0 (funda��ão);
  • Fatia 1.1 (busca de vagas sobre a seed);
  • Fatia 1.2 (ingestão de vagas reais da Remotive, com worker BullMQ);
  • globot com Greenhouse e Lever (adiantado da Fase 2) e importação autenticada na API.

Próxima: Fatia 1.3, identidade.

Fontes de vagas: só fontes oficiais. O projeto não raspa o Glassdoor nem outros sites. Cada fonte tem os termos de uso aplicados no código. A Remotive aceita no máximo 4 consultas por dia e exige atribuição. Não aumente a frequência no job_sources.config: o worker recusa uma agenda acima do teto.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages