Skip to content

Repository files navigation

StackHire

A Telegram bot that finds developer jobs from your plain-text description of what you want.

Live Demo TypeScript Bun Next.js PostgreSQL Docker License


What is StackHire?

Job boards expect developers to navigate filters, checkboxes, and keyword fields. StackHire removes that friction — you describe your ideal role in plain English inside Telegram, and it queries the Adzuna job API live, scores every result against your tech stack, role type, seniority, and location, and returns ranked listings with direct apply links. Your preferences are persisted (with hashed IDs for privacy) so repeat queries get smarter over time.

Live demo → stackhire.tanisheesh.in — landing page and docs. Telegram bot → t.me/StackHireBot — no login, no signup, start typing.


What you get

  • Natural language query parsing — extracts tech stack, role type, seniority, location, and remote preference from free-text without an LLM; fully deterministic and auditable.
  • DB-first, live-fallback search — serves cached Adzuna results for speed; falls back to a live API call when fewer than 15 matches exist for your specific query.
  • Weighted relevance ranking — scores each listing across five dimensions (tech tags, role type, seniority, location, remote) and returns the top matches sorted by score.
  • Per-user preference profiles — saves your last query as a profile (SHA-256 hashed Telegram ID) so future empty queries fall back to your saved stack and preferences.
  • Paginated results with "Show more" — delivers 5 results per page via Telegram inline keyboard; background scraper refreshes the DB every 6 hours and marks stale listings expired.

Stack

Layer Tech
Bot runtime Bun 1.x · TypeScript 5 · Telegraf 4
Web (landing) Next.js 16 · React 19 · Tailwind CSS 4
Database PostgreSQL 16 · postgres (npm)
Job data Adzuna REST API
Scraping Playwright (Chromium) — LinkedIn, Indeed, Remotive scrapers (built, not wired in v1)
Infra Docker · Docker Compose · Render

Engineering Decisions

Why Bun over Node.js? Bun's built-in TypeScript runner removes the transpile step, ships a native test runner, and is faster for I/O-heavy workloads — no extra tooling required.

Why deterministic scoring over an LLM for matching? Every score is traceable to its inputs: +2 per matching tech tag, +3 for role type, +3 for location, etc. No prompt tuning, no rate limits, no hallucinated relevance. The tradeoff is that it can't understand synonyms ("JS" vs "JavaScript") — mitigated by the parser's canonical keyword map.

Why DB-first with live fallback, rather than always querying the API? The Adzuna free tier has rate limits. Serving the background-scraped cache for common queries is instant and free; the live call only fires when the cache is thin for an unusual query/location combination.

Why SHA-256 hash Telegram user IDs before storage? Telegram user IDs are stable identifiers. Hashing before writes means the DB never contains a value that can be reverse-mapped to a real identity — preference profiles are linked only to the hash.


Docs

Document Description
PRD Product requirements — goals, user stories, non-goals
Architecture System design, data flow, component breakdown
Decisions Every major technical decision and why
Setup Local dev setup, env vars, deployment

Author

Tanish Poddartanisheesh.in · LinkedIn · GitHub

About

Telegram bot that parses plain-text job queries, searches Adzuna across 5 countries with DB-first caching, and ranks results with a weighted scoring algorithm.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages