automation · n8n · 2026

Job Hunter

A pipeline that reads every job listing for me and only pings me about the ones I'm actually allowed to take.

roleSolo
sourcesLinkedIn · Indeed
cadence4 runs / day, an hour apart
statusStill in use
n8n workflow for Job Hunter
the full n8n workflow — scrape, dedupe, score, store, notify
01 — why

As a DOST-SEI scholar I owe a Return of Service: my employer has to be a Philippine-registered entity. No job board lets you filter for that.

“Remote” doesn’t tell you whether a company can issue a Philippine Certificate of Employment. Checking that by hand — on top of stack fit and experience level — was the real bottleneck. Job Hunter automates the screening, not the applying.

RA 2067 · in shortServe in the Philippines, ideally in your field, for as long as the scholarship lasted — at a Philippine-registered employer or a valid EOR.
02 — one run
105 in, 12 worth reading
105
scraped · 6 search terms × 2 sites
81
after within-batch dedup
60
after cross-run dedup (Postgres)
12
passed ROS and scored 5+ → Telegram
03 — how a job is judged
Three gates, then a capped score

Gemini gets my background, the ROS rules and a rubric, and returns a JSON verdict. Fail any gate and the score is 0. Pass all three and four capped categories add up to at most 10 — so a job can never score its way past 10 by piling up flags. Telegram only fires at 5+.

gate 1fail → 0
ROS complianceIs the employer a Philippine-registered entity, or a valid EOR? If not, stop.
gate 2fail → OLD JOB POST
FreshnessPosted more than a month ago? Not worth the application.
gate 3fail → LOCATION FAR
LocationOnsite or frequent hybrid must be within ~100 km of Santa Cruz, Laguna. Fully remote skips this.
score · 0–10notify ≥ 5
Stack fit0–3
NestJS, or 3+ of my core skills, scores highest.
Experience0–2
Penalises reach roles asking for far more years than I have.
Green / red flags0–3
Company signals, contract language, time tracking, 2+ office days.
Salary0–2
Partial credit for close-but-under postings.
Telegram job match messages
04 — what lands on my phone
Score, flags, and the reasoning — so I can decide in seconds

Every job is stored in Postgres with its verdict, pass or fail. Only matches reach Telegram. A separate Error Trigger sends its own alert, so a crash never looks like an empty job market.

05 — what I learned
The parts that bit me
Pinned test data hid broken wiringThe search-terms node was disconnected, but its pinned output kept manual tests passing. The first scheduled run failed instantly. Now I unpin and re-test from a cold trigger before trusting a workflow.
Free-tier limits picked the modelGemini 1.5–2.5 Flash and Groq hit rate limits fast — some as low as 5 requests a day. Gemini 3.1 Flash Lite (15 RPM, 500 RPD) plus a batch-of-1 loop with a 5–10 s wait keeps it under the ceiling.
Rotate offsets instead of re-scrapingBoards return the same top results every time. A small table tracks an offset per search term (0 → 10 → 20 → 30 → 0), so each run samples a new slice.
Two layers of dedupA Set-based check catches the same job under multiple terms; a Postgres lookup on job_id catches anything seen before. ON CONFLICT DO NOTHING is only the safety net.
06 — stack
orchestrationn8n, self-hosted with Docker Compose
scrapingPython · JobSpy · Flask wrapper
databasePostgreSQL — isolated app schema
llmGoogle Gemini 3.1 Flash Lite
notificationsTelegram Bot API
infraDocker Compose
07 — where it is now

Still running and still useful. Most rejections are correct — junior NestJS roles in the Philippines are genuinely thin, and the stack matches usually skew senior, which the model flags as REACH ROLE instead of a strong fit.