Note: This project is a work in progress. Features may be incomplete or change.
A self-hosted LinkedIn job scraping and tracking application built with Go. Scrapes job listings from LinkedIn, stores them in PostgreSQL, and provides a web UI to browse, filter, and track your job applications.
- Configure scrapers — Set up search parameters (keywords, location, job type, experience level) via the admin panel
- Scrape jobs — The scraper fetches job listings from LinkedIn's public guest API, parses HTML with goquery, and stores results in PostgreSQL
- Fetch JDs — Job descriptions are fetched individually and parsed for details (seniority, employment type, salary range, applicants)
- Browse & filter — View all jobs with search, sort, filter by date/location/company
- View JD — Click any job to open the full description in a modal. Navigate between jobs with arrow keys. Years of experience are highlighted automatically
- Track applications — Jobs move through stages (new → viewed → draft → applied). The Kanban tracker shows all in-progress applications
- Manage companies — Block irrelevant companies to hide their jobs. Classify companies by type
| Jobs List | JD Viewer |
|---|---|
| Companies | Admin Panel |
|---|---|
- Job Scraping — Automated scraping of LinkedIn job listings with configurable search parameters
- Job Details — Fetches full job descriptions, salary ranges, seniority levels, and application status
- Job List — Browse jobs with search, filter, sort, and pagination
- JD Viewer — Full-screen modal with keyboard navigation (arrow keys) between jobs
- Application Tracker — Kanban board with drag-and-drop swim lanes (Draft, Applied, Offered, Rejected)
- Stage Tracking — Automatic stage progression (new → viewed → draft → applied → offered)
- Company Management — Block companies, classify as product/service-based, view job counts
- Admin Panel — Configure scrapers, view run history, manage companies, error logs
- Dark Mode — Toggle between light and dark themes (persisted in localStorage)
- Backend: Go, Chi router, GORM ORM
- Database: PostgreSQL
- Frontend: Server-rendered HTML templates, Bootstrap 5, SortableJS
- Scraping: goquery (HTML parsing), random user agents, rate limiting with retry
├── main.go # Entry point, server setup, graceful shutdown
├── internal/
│ ├── config/ # Environment config
│ ├── database/ # PostgreSQL connection
│ ├── handlers/ # HTTP handlers
│ │ ├── pages.go # Page rendering (jobs, admin, dashboard)
│ │ ├── jobs.go # Job API handlers (adjacent, stage, tracker)
│ │ ├── scrap.go # Scraper handlers
│ │ └── companies.go # Company handlers
│ ├── middleware/ # Custom request logger
│ ├── models/ # GORM models
│ │ ├── job.go # Job, JobDetail, JobStats, JobStageHistory, JobNote
│ │ ├── company.go # Company
│ │ ├── scrape_params.go # Scrape configuration with enums
│ │ └── scrape_stats.go # Scrape run statistics
│ ├── repository/ # Data access layer
│ │ ├── job.go # Job CRUD, filtering, adjacent jobs
│ │ ├── jobs_stats.go # Stage tracking, notes
│ │ ├── company.go # Company CRUD with stats
│ │ └── scrape_stats.go # Scrape run tracking
│ ├── router/ # Route definitions
│ └── services/ # LinkedIn scraper service
├── templates/ # Go HTML templates
│ ├── layout.html # Main layout with navbar
│ ├── admin_layout.html # Admin layout with sidebar
│ ├── jobs.html # Job listing page
│ ├── tracker.html # Kanban tracker board
│ ├── companies.html # Public companies list
│ ├── admin.html # Scrape config + run history
│ ├── admin_dashboard.html # Admin dashboard
│ ├── admin_companies.html # Admin companies table
│ └── partials/ # Reusable template components
│ ├── jd_modal.html # JD viewer modal
│ └── navbar.html # Shared navigation bar
├── static/
│ ├── css/style.css # Custom styles
│ └── js/app.js # Client-side logic
└── .env # Environment variables
- Go 1.21+
- PostgreSQL
git clone https://github.com/aliasgar55/JobTracker.git
cd JobTracker
go mod downloadCreate a .env file:
DATABASE_URL=postgres://user:password@localhost:5432/linkedin_jobs?sslmode=disable
PORT=6970go run main.goThe application will:
- Connect to PostgreSQL
- Auto-migrate all models
- Start the HTTP server on the configured port
# Current platform
go build -o bin/server main.go
# Cross-compile for Windows
GOOS=windows GOARCH=amd64 go build -o bin/server.exe main.go
# Cross-compile for Linux
GOOS=linux GOARCH=amd64 go build -o bin/server main.go| Method | Path | Description |
|---|---|---|
| GET | /jobs |
Job listings with search/filter/sort |
| GET | /companies |
Public companies list |
| GET | /tracker |
Kanban application tracker |
| GET | /admin |
Admin dashboard |
| GET | /admin/scrape-config |
Scraper configuration |
| GET | /admin/companies |
Admin companies management |
| GET | /admin/errors |
Error logs |
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/internal/jobs/{id} |
Get job detail |
| GET | /api/v1/internal/jobs/{id}/adjacent |
Get prev/next job IDs |
| POST | /api/v1/internal/jobs/{id}/stage |
Update job stage |
| POST | /api/v1/internal/scrap |
Run all scrapers |
| POST | /api/v1/internal/scrap/jd |
Fetch all unfetched JDs |
| POST | /api/v1/internal/scrap/{jobId}/detail |
Fetch single job detail |
Jobs progress through stages (never downgrade):
new → viewed → draft → applied → offered
→ rejected
- new — Never opened
- viewed — Opened in JD modal
- draft — Clicked "Apply on LinkedIn"
- applied — Confirmed application
- offered — Received offer
- rejected — Application rejected