Telegram bot that aggregates Azerbaijani job vacancies hourly and notifies users based on their subscribed fields. It runs on Cloudflare Workers with TypeScript, grammY, D1, Cron Triggers, and static HTML scraping.
npm install
copy .dev.vars.example .dev.vars
npx wrangler d1 create vakansiya-bot
npm run db:apply:local
npm run devFill .dev.vars with local BOT_TOKEN and WEBHOOK_SECRET. For production, set secrets through Wrangler:
npx wrangler secret put BOT_TOKEN
npx wrangler secret put WEBHOOK_SECRETApply schema locally and remotely:
npm run db:apply:local
npm run db:apply:remotewrangler.toml must contain the D1 database_id returned by npx wrangler d1 create vakansiya-bot.
npm run typecheck
npm test
npm run devWorking scrapers:
boss.az(first 3 listing pages)hellojob.az(first 3 listing pages)jobsearch.azsmartjob.azjobs.glorri.az
Skipped sources are documented in progress.md.
Search breadth:
Dar(strict) only sends exact title matches.Normalmatches title tokens and synonyms.Genişalso searches company, location, and description-like text when a scraper provides it.
npm run deploy
npm run set-webhook -- https://<your-worker>.workers.devCurrent deployed Worker URL:
https://vakansiya-bot.polyana-eam.workers.dev
In Telegram, open the bot and run:
/start
/ixtisas backend developer
/ixtisaslar
/genislik
/axtar
Expected result: /axtar replies that search started, then sends a vacancy batch if new matching jobs are found, or says that no new matching vacancy was found.
The Worker logs structured JSON events:
scraper_completescraper_failedpipeline_completepipeline_failedbot_error
Use:
npm run tailCron is configured for 7 * * * *. Old sent-vacancy fingerprints are pruned daily during the Baku-local 03:xx run.