<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex Moussavi</title>
    <description>The latest articles on DEV Community by Alex Moussavi (@alex_m_137).</description>
    <link>https://dev.to/alex_m_137</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4084249%2F664a5045-3540-42ab-b3af-26812b5f770b.png</url>
      <title>DEV Community: Alex Moussavi</title>
      <link>https://dev.to/alex_m_137</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alex_m_137"/>
    <language>en</language>
    <item>
      <title>I built a real-time job board watcher that alerts you the second a matching job goes live</title>
      <dc:creator>Alex Moussavi</dc:creator>
      <pubDate>Wed, 19 Aug 2026 04:48:02 +0000</pubDate>
      <link>https://dev.to/alex_m_137/i-built-a-real-time-job-board-watcher-that-alerts-you-the-second-a-matching-job-goes-live-3ni1</link>
      <guid>https://dev.to/alex_m_137/i-built-a-real-time-job-board-watcher-that-alerts-you-the-second-a-matching-job-goes-live-3ni1</guid>
      <description>&lt;p&gt;A few months ago I got tired of how job hunting actually works. You find a role you like, you apply, and then you realize it was posted three days ago and already has 400 applicants. By the time a job shows up in your normal scroll, you're already late.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://findmejobs.co" rel="noopener noreferrer"&gt;FindMeJobs&lt;/a&gt; to flip that around. Instead of me checking job boards, it checks them for me, constantly, and messages me the second something matches what I'm actually looking for.&lt;/p&gt;

&lt;p&gt;Here is how it is put together.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea
&lt;/h2&gt;

&lt;p&gt;You define a search once: keywords, boolean include/exclude rules, location, and so on. From then on a pipeline scrapes fresh postings every few minutes, filters them against your rules, runs the survivors through an AI relevance check, and if something matches you get a Telegram or email alert within minutes of it going live.&lt;/p&gt;

&lt;p&gt;Being early is basically the entire value, so the whole system is built around latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;The app itself is a fairly standard T3-style setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 16&lt;/strong&gt; (App Router) + React + TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tRPC&lt;/strong&gt; for end-to-end typed APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drizzle ORM&lt;/strong&gt; on &lt;strong&gt;Postgres&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase&lt;/strong&gt; for auth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stripe&lt;/strong&gt; for subscriptions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind + shadcn/ui&lt;/strong&gt; on the frontend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing exotic there. The interesting part is the scraping and notification pipeline, which does not live inside the Next.js app at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeline (the actually hard part)
&lt;/h2&gt;

&lt;p&gt;Scraping runs entirely on &lt;strong&gt;Cloudflare Workers + Queues&lt;/strong&gt; on a cron schedule:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An &lt;strong&gt;orchestrator&lt;/strong&gt; worker wakes up on a schedule, pulls every active search from the DB, and enqueues scrape jobs.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;consumer&lt;/strong&gt; worker runs the scrape and pushes raw results onto a filter queue.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;cheap keyword filter&lt;/strong&gt; worker applies the boolean rules first, so I am not paying for an LLM call on obviously irrelevant jobs.&lt;/li&gt;
&lt;li&gt;Whatever survives goes to an &lt;strong&gt;AI filter&lt;/strong&gt; for relevance scoring and short summaries.&lt;/li&gt;
&lt;li&gt;Matches hit a &lt;strong&gt;notification&lt;/strong&gt; worker that sends the Telegram or email alert.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Splitting it into queue stages meant each step scales on its own, and one slow scrape never blocks notifications for a different user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that bit me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full-text search at scale.&lt;/strong&gt; Postgres GIN indexes on job descriptions made search usable, but I had to be careful about when queries fall back between the ORM and raw SQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable scraping.&lt;/strong&gt; This was by far the hardest part and where most of my time went. Getting fresh data consistently, without things quietly breaking, took more iteration than the rest of the app combined.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency vs cost.&lt;/strong&gt; Running an LLM on every scraped job would be both slow and expensive, which is the whole reason the cheap filter runs before the AI one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  If you want to poke at it
&lt;/h2&gt;

&lt;p&gt;The product is live at &lt;a href="https://findmejobs.co" rel="noopener noreferrer"&gt;findmejobs.co&lt;/a&gt;, and I put up a repo with more detail and a discussions space here: &lt;a href="https://github.com/ali-moussavi/findmejobs" rel="noopener noreferrer"&gt;https://github.com/ali-moussavi/findmejobs&lt;/a&gt;. Happy to get into the architecture in the comments.&lt;/p&gt;

&lt;p&gt;And if you have job hunted recently, I would honestly like to hear which part of the process annoyed you the most. That is mostly what I have been building against.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
