A full-stack job platform with AI-powered resume matching, real-time job search, and employer tools. Built with FastAPI, React, PostgreSQL, Pinecone, and OpenAI.
- Job Board — Browse 500+ real jobs scraped from the Adzuna API across 10 tech categories
- AI Resume Matching — Upload your resume and get ranked job matches powered by OpenAI embeddings and Pinecone vector search
- Smart Filters — Filter by location, job type, remote, and salary range
- Sort Options — Most recent, Highest salary, Best AI match, Most relevant
- Job Modal — Click any job card for full details, requirements, and a direct "Apply now" link
- Employer Dashboard — Post and manage job listings
- Seeker Dashboard — Upload resume, view detected skills, see AI-scored matches
- Dark / Light Mode — Persistent theme toggle in the navbar
- Auth — JWT-based login and registration with role-based access (seeker / employer)
| Layer | Technology |
|---|---|
| Framework | FastAPI (async) |
| Database | PostgreSQL 16 + SQLAlchemy (async) |
| Migrations | Alembic |
| Auth | JWT (python-jose) + bcrypt |
| AI Embeddings | OpenAI text-embedding-3-small |
| Vector Search | Pinecone |
| LLM | OpenAI GPT-3.5-turbo via LangChain |
| Job Data | Adzuna Jobs API |
| Cache | Redis |
| HTTP Client | httpx |
| Layer | Technology |
|---|---|
| Framework | React 18 + TypeScript |
| Build Tool | Vite |
| Styling | Tailwind CSS + shadcn/ui |
| Animations | Framer Motion |
| State | Zustand (auth + theme) |
| Data Fetching | TanStack Query (React Query) |
| Routing | React Router v6 |
| Forms | React Hook Form + Zod |
| Service | Technology |
|---|---|
| Database | Docker (postgres:16) |
| Cache | Docker (redis:7-alpine) |
job-platform/
├── backend/
│ ├── app/
│ │ ├── core/ # Config, database, dependencies
│ │ ├── models/ # SQLAlchemy models (User, Job, Application)
│ │ ├── routers/ # API routes (auth, jobs, users, matching)
│ │ ├── schemas/ # Pydantic request/response schemas
│ │ ├── services/ # Business logic (embeddings, AI agent, scraper)
│ │ └── main.py # FastAPI app entry point
│ └── alembic/ # Database migrations
├── frontend/
│ └── src/
│ ├── components/ # Reusable UI components
│ ├── pages/ # Route-level page components
│ ├── stores/ # Zustand state (auth, theme)
│ ├── types/ # Shared TypeScript interfaces
│ └── lib/ # Utilities (api client, helpers)
└── docker-compose.yml
git clone https://github.com/your-username/job-platform.git
cd job-platformdocker-compose up -dThis starts:
- PostgreSQL on
localhost:5433 - Redis on
localhost:6379
cd backend
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -r requirements.txtCreate backend/.env:
DATABASE_URL=postgresql+asyncpg://postgres:postgres123@localhost:5433/jobplatform
REDIS_URL=redis://localhost:6379
SECRET_KEY=your-secret-key-here
# OpenAI — https://platform.openai.com/api-keys
OPENAI_API_KEY=sk-...
# Pinecone — https://app.pinecone.io
PINECONE_API_KEY=pcsk_...
PINECONE_INDEX_NAME=job-embeddings
# Adzuna — https://developer.adzuna.com
ADZUNA_APP_ID=your-app-id
ADZUNA_APP_KEY=your-app-keyRun the server:
uvicorn app.main:app --reload --port 8000API docs available at http://localhost:8000/docs
cd frontend
npm install # or: bun install
npm run dev # or: bun devApp runs at http://localhost:5173
With the backend running, call the seed endpoint to populate jobs from Adzuna across 10 tech categories:
curl -X POST "http://localhost:8000/api/jobs/seed"This fetches ~500 real jobs (software engineer, frontend, backend, data engineer, ML engineer, DevOps, cloud, mobile, product manager, data scientist).
To enable the "Best match" AI sort, embed all jobs into Pinecone:
# Requires a logged-in user token
curl -X POST "http://localhost:8000/api/match/embed-jobs" \
-H "Authorization: Bearer YOUR_TOKEN"| Method | Endpoint | Description |
|---|---|---|
POST |
/api/auth/register |
Register a new user |
POST |
/api/auth/login |
Login, returns JWT |
GET |
/api/jobs |
List jobs (search, filter, sort, paginate) |
GET |
/api/jobs/{id} |
Get a single job |
POST |
/api/jobs |
Create a job (employer only) |
POST |
/api/jobs/seed |
Seed jobs from Adzuna |
GET |
/api/users/me |
Get current user profile |
POST |
/api/users/me/resume |
Upload resume text |
POST |
/api/match/from-profile |
AI match jobs to saved resume |
POST |
/api/match/embed-jobs |
Embed all jobs into Pinecone |
GET |
/health |
Health check |
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL async connection string |
REDIS_URL |
Yes | Redis connection string |
SECRET_KEY |
Yes | JWT signing secret (generate with openssl rand -hex 32) |
OPENAI_API_KEY |
Yes | For embeddings and LLM matching |
PINECONE_API_KEY |
Yes | For vector search |
PINECONE_INDEX_NAME |
Yes | Name of your Pinecone index |
ADZUNA_APP_ID |
Yes | For job scraping |
ADZUNA_APP_KEY |
Yes | For job scraping |
MIT