# rdlucas2/jobregator architecture

> Architecture diagram of the GitHub repository rdlucas2/jobregator, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-14). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/rdlucas2/jobregator
- Repository: https://github.com/rdlucas2/jobregator
- Video tour (about a minute): https://gitdiagram.com/rdlucas2/jobregator/video

## Overview

Jobregator aggregates job listings from multiple sources, filters them, enriches them with AI, stores them, then surfaces them through Discord notifications and a searchable dashboard with live updates. The diagram follows the documented service workflow and source excerpts; some internal wiring is unsampled, so those relationships are omitted rather than inferred.

Main entry points: [`services/worker/src/worker.py`](https://github.com/rdlucas2/jobregator/blob/main/services/worker/src/worker.py) (Worker Consumer), [`services/dashboard/src/index.ts`](https://github.com/rdlucas2/jobregator/blob/main/services/dashboard/src/index.ts) (Dashboard Routes & SSE), [`services/scraper/cmd/scraper/main.go`](https://github.com/rdlucas2/jobregator/blob/main/services/scraper/cmd/scraper/main.go) (Scraper Orchestrator), [`services/mcp-server/src/server.py`](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/server.py) (MCP Enrichment Server)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_collection["Collection &amp; Filtering"]
  node_scraper["Scraper Orchestrator<br/>[main.go]"]
  node_source_adapters["Source Adapters"]
  node_hard_filters["Lookback &amp; Hard Filters"]
end

subgraph group_enrichment["AI Enrichment"]
  node_worker["Worker Consumer<br/>[worker.py]"]
  node_mcp_server["MCP Enrichment Server<br/>[server.py]"]
  node_enrichment_tools["Analysis &amp; Scoring Tools<br/>[tools.py]"]
  node_provider_factory["Provider Selection &amp; Cache<br/>[factory.py]"]
  node_provider_contracts["Provider Contracts<br/>[base.py]"]
  node_claude_provider["Claude Providers<br/>[claude.py]"]
  node_jev_provider["Jev Decisions<br/>[jev.py]"]
  node_claude_llm["Claude API Client<br/>[llm.py]"]
end

subgraph group_persistence["Storage &amp; Messaging"]
  node_nats["NATS Streams"]
  node_worker_db["Listing Persistence<br/>[db.py]"]
  node_postgres[("Postgres Listings")]
end

subgraph group_delivery["User Delivery"]
  node_notifier["Discord Notifier<br/>[notifier.py]"]
  node_dashboard["Dashboard Routes &amp; SSE<br/>[index.ts]"]
  node_dashboard_db["Dashboard Queries<br/>[db.ts]"]
  node_templates["Dashboard Views &amp; Charts<br/>[templates.ts]"]
end

node_sources(("Job Sources"))
node_anthropic{{"Anthropic Claude API"}}
node_typesafe{{"TypeSafe API"}}
node_discord{{"Discord"}}
node_user(("Dashboard User"))

node_sources -->|"provide listings"| node_source_adapters
node_scraper -->|"fetches listings"| node_source_adapters
node_scraper -->|"filters listings"| node_hard_filters
node_scraper -->|"publishes raw"| node_nats
node_nats -->|"delivers raw"| node_worker
node_worker -->|"inserts &amp; updates"| node_worker_db
node_worker_db -->|"writes listings"| node_postgres
node_worker -->|"calls MCP tools"| node_mcp_server
node_mcp_server -->|"dispatches analysis"| node_enrichment_tools
node_mcp_server -->|"builds providers"| node_provider_factory
node_provider_factory -->|"selects provider"| node_claude_provider
node_provider_factory -->|"selects provider"| node_jev_provider
node_claude_provider -->|"implements contracts"| node_provider_contracts
node_jev_provider -->|"implements decisions"| node_provider_contracts
node_claude_provider -->|"requests completions"| node_claude_llm
node_claude_llm -->|"calls API"| node_anthropic
node_jev_provider -.->|"requests decisions"| node_typesafe
node_worker -->|"publishes enriched"| node_nats
node_nats -->|"delivers enriched"| node_notifier
node_notifier -->|"sends webhook"| node_discord
node_nats -->|"streams updates"| node_dashboard
node_dashboard -->|"queries listings"| node_dashboard_db
node_dashboard_db -->|"reads listings"| node_postgres
node_dashboard -->|"renders views"| node_templates
node_user -->|"browses &amp; filters"| node_dashboard

click node_scraper "https://github.com/rdlucas2/jobregator/blob/main/services/scraper/cmd/scraper/main.go"
click node_source_adapters "https://github.com/rdlucas2/jobregator/tree/main/services/scraper/internal/source"
click node_hard_filters "https://github.com/rdlucas2/jobregator/tree/main/services/scraper/internal/source"
click node_worker "https://github.com/rdlucas2/jobregator/blob/main/services/worker/src/worker.py"
click node_worker_db "https://github.com/rdlucas2/jobregator/blob/main/services/worker/src/db.py"
click node_mcp_server "https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/server.py"
click node_enrichment_tools "https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/tools.py"
click node_provider_factory "https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/factory.py"
click node_provider_contracts "https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/base.py"
click node_claude_provider "https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/claude.py"
click node_jev_provider "https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/jev.py"
click node_claude_llm "https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/llm.py"
click node_notifier "https://github.com/rdlucas2/jobregator/blob/main/services/notifier/src/notifier.py"
click node_dashboard "https://github.com/rdlucas2/jobregator/blob/main/services/dashboard/src/index.ts"
click node_dashboard_db "https://github.com/rdlucas2/jobregator/blob/main/services/dashboard/src/db.ts"
click node_templates "https://github.com/rdlucas2/jobregator/blob/main/services/dashboard/src/templates.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_scraper,node_source_adapters,node_hard_filters,node_user toneBlue
class node_worker,node_mcp_server,node_enrichment_tools,node_provider_factory,node_provider_contracts,node_claude_provider,node_jev_provider,node_claude_llm toneAmber
class node_nats,node_worker_db,node_postgres,node_anthropic,node_typesafe toneMint
class node_notifier,node_dashboard,node_dashboard_db,node_templates toneRose
class node_sources,node_discord toneIndigo
```

## Components

### Collection & Filtering

- [Scraper Orchestrator](https://github.com/rdlucas2/jobregator/blob/main/services/scraper/cmd/scraper/main.go): `services/scraper/cmd/scraper/main.go`
- [Source Adapters](https://github.com/rdlucas2/jobregator/tree/main/services/scraper/internal/source): `services/scraper/internal/source`
- [Lookback & Hard Filters](https://github.com/rdlucas2/jobregator/tree/main/services/scraper/internal/source): `services/scraper/internal/source`

### AI Enrichment

- [Worker Consumer](https://github.com/rdlucas2/jobregator/blob/main/services/worker/src/worker.py): `services/worker/src/worker.py`
- [MCP Enrichment Server](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/server.py): `services/mcp-server/src/server.py`
- [Analysis & Scoring Tools](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/tools.py): `services/mcp-server/src/tools.py`
- [Provider Selection & Cache](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/factory.py): `services/mcp-server/src/providers/factory.py`
- [Provider Contracts](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/base.py): `services/mcp-server/src/providers/base.py`
- [Claude Providers](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/claude.py): `services/mcp-server/src/providers/claude.py`
- [Jev Decisions](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/providers/jev.py): `services/mcp-server/src/providers/jev.py`
- [Claude API Client](https://github.com/rdlucas2/jobregator/blob/main/services/mcp-server/src/llm.py): `services/mcp-server/src/llm.py`

### Storage & Messaging

- **NATS Streams**
- [Listing Persistence](https://github.com/rdlucas2/jobregator/blob/main/services/worker/src/db.py): `services/worker/src/db.py`
- **Postgres Listings**

### User Delivery

- [Discord Notifier](https://github.com/rdlucas2/jobregator/blob/main/services/notifier/src/notifier.py): `services/notifier/src/notifier.py`
- [Dashboard Routes & SSE](https://github.com/rdlucas2/jobregator/blob/main/services/dashboard/src/index.ts): `services/dashboard/src/index.ts`
- [Dashboard Queries](https://github.com/rdlucas2/jobregator/blob/main/services/dashboard/src/db.ts): `services/dashboard/src/db.ts`
- [Dashboard Views & Charts](https://github.com/rdlucas2/jobregator/blob/main/services/dashboard/src/templates.ts): `services/dashboard/src/templates.ts`

### Other components

- **Job Sources**
- **Anthropic Claude API**
- **TypeSafe API**
- **Discord**
- **Dashboard User**

## Connections

- Job Sources → Source Adapters: provide listings (evidence: `services/scraper/internal/source/adzuna.go`)
- Scraper Orchestrator → Source Adapters: fetches listings (evidence: `services/scraper/cmd/scraper/main.go`)
- Scraper Orchestrator → Lookback & Hard Filters: filters listings (evidence: `services/scraper/cmd/scraper/main.go`)
- Scraper Orchestrator → NATS Streams: publishes raw (evidence: `services/scraper/cmd/scraper/main.go`)
- NATS Streams → Worker Consumer: delivers raw (evidence: `README.md`)
- Worker Consumer → Listing Persistence: inserts & updates (evidence: `services/worker/src/worker.py`)
- Listing Persistence → Postgres Listings: writes listings (evidence: `services/worker/src/db.py`)
- Worker Consumer → MCP Enrichment Server: calls MCP tools (evidence: `services/worker/src/worker.py`)
- MCP Enrichment Server → Analysis & Scoring Tools: dispatches analysis (evidence: `services/mcp-server/src/server.py`)
- MCP Enrichment Server → Provider Selection & Cache: builds providers (evidence: `services/mcp-server/src/server.py`)
- Provider Selection & Cache → Claude Providers: selects provider (evidence: `services/mcp-server/src/providers/factory.py`)
- Provider Selection & Cache → Jev Decisions: selects provider (evidence: `services/mcp-server/src/providers/factory.py`)
- Claude Providers → Provider Contracts: implements contracts (evidence: `services/mcp-server/src/providers/claude.py`)
- Jev Decisions → Provider Contracts: implements decisions (evidence: `services/mcp-server/src/providers/jev.py`)
- Claude Providers → Claude API Client: requests completions (evidence: `services/mcp-server/src/providers/claude.py`)
- Claude API Client → Anthropic Claude API: calls API (evidence: `services/mcp-server/src/llm.py`)
- Jev Decisions → TypeSafe API: requests decisions
- Worker Consumer → NATS Streams: publishes enriched (evidence: `services/worker/src/worker.py`)
- NATS Streams → Discord Notifier: delivers enriched (evidence: `README.md`)
- Discord Notifier → Discord: sends webhook (evidence: `README.md`)
- NATS Streams → Dashboard Routes & SSE: streams updates (evidence: `services/dashboard/src/index.ts`)
- Dashboard Routes & SSE → Dashboard Queries: queries listings (evidence: `services/dashboard/src/index.ts`)
- Dashboard Queries → Postgres Listings: reads listings (evidence: `services/dashboard/src/db.ts`)
- Dashboard Routes & SSE → Dashboard Views & Charts: renders views (evidence: `services/dashboard/src/index.ts`)
- Dashboard User → Dashboard Routes & SSE: browses & filters (evidence: `README.md`)
