A full-stack job tracking app that monitors GitHub repositories for new internship postings, filters for US-only roles, and delivers a consolidated HTML digest email whenever new listings are detected.
Stack: Python · Flask · SQLite · APScheduler · BeautifulSoup · React · TypeScript · Tailwind CSS v4
- Scrapes SimplifyJobs README tables on a configurable schedule
- Filters to US-only postings using state abbreviation and keyword detection
- Only surfaces jobs posted within the last 0–1 days — no stale listings
- Sends a single HTML digest email per run instead of one email per job
- React dashboard with job search, date range filters, run history, and manual trigger
- REST API with pagination, filtering by company/role/location/date
job-tracker/
├── .env.example # Copy to .env and fill in your values
├── backend/
│ ├── app/
│ │ ├── __init__.py # App factory
│ │ ├── config.py # Env var loading + validation
│ │ ├── db.py # SQLite helpers
│ │ ├── scraper.py # GitHub README scraper
│ │ ├── notifier.py # Gmail digest emails
│ │ ├── scheduler.py # APScheduler background job
│ │ └── routes.py # Flask REST API blueprint
│ ├── run.py # Entry point
│ ├── seed.py # One-time DB seed (marks existing jobs as notified)
│ └── requirements.txt
└── frontend/
├── src/
│ ├── pages/ # Dashboard, JobsList, Repos
│ ├── lib/ # API client + types
│ └── App.tsx
└── package.json
- Python 3.11+
- Node.js 18+
- A GitHub Personal Access Token (read-only, public repos)
- A Gmail account with an App Password enabled (requires 2FA)
git clone https://github.com/your-username/githired.git
cd githired/job-trackercp .env.example .envEdit .env:
GITHUB_TOKEN="ghp_yourtoken"
EMAIL_SENDER="[email protected]"
EMAIL_PASSWORD="your-app-password" # Gmail App Password, NOT your account password
EMAIL_RECIPIENT="[email protected]"
CHECK_INTERVAL_MINUTES=120 # How often the scraper runs
DATABASE_PATH=jobs.db
FLASK_SECRET_KEY="change-me"
FILTER_COUNTRY=USA # Leave blank to skip country filteringcd backend
python -m venv venv
# Windows
.\venv\Scripts\activate
# macOS / Linux
source venv/bin/activate
pip install -r requirements.txtThis marks all currently listed jobs as already-notified so you don't get flooded with emails on first run:
python seed.pycd ../frontend
npm installOpen two terminals.
Terminal 1 — Backend
cd backend
.\venv\Scripts\activate # Windows
python run.pyFlask starts on http://localhost:5000.
Terminal 2 — Frontend
cd frontend
npm run devVite starts on http://localhost:5173.
Once the backend is running, add a repo via the Repos page in the UI, or via the API:
curl -X POST http://localhost:5000/api/repos \
-H "Content-Type: application/json" \
-d '{"owner": "SimplifyJobs", "name": "Summer2026-Internships"}'The scheduler will scrape it automatically on the next interval. You can also trigger a manual run from the Dashboard.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
App status + total jobs |
GET |
/api/jobs |
Paginated jobs (?company=&role=&location=&date_posted=&posted_after=&page=&per_page=) |
GET |
/api/jobs/new |
Jobs in a time window (?min_hours=0&max_hours=24) |
DELETE |
/api/jobs |
Clear all jobs |
GET |
/api/repos |
List monitored repos |
POST |
/api/repos |
Add a repo {"owner": "", "name": ""} |
POST |
/api/run |
Manually trigger a scrape run |
GET |
/api/runs |
Last 20 run log entries |
- Enable 2-Factor Authentication on your Google account
- Go to myaccount.google.com/apppasswords
- Generate an App Password for "Mail"
- Use that 16-character password as
EMAIL_PASSWORDin.env— not your regular Gmail password