Pursuiter: AI-assisted job matching platform by Mohammad Al-QasemPursuiter: AI-assisted job matching platform by Mohammad Al-Qasem

Pursuiter: AI-assisted job matching platform

Mohammad Al-Qasem

Mohammad Al-Qasem

Pursuiter

A two-sided AI job board that flips the signal-to-noise ratio: applicants get pre-application feedback, recruiters get fewer-but-better-qualified applications.

Overview

Pursuiter is a job-application platform with a twist on both sides:
For applicants — paste your résumé and a job listing, and a Gemini-powered analyzer grades fit, surfaces missing skills, and suggests phrasing tweaks before you submit.
For recruiters — set explicit minimum criteria (skills, years, education) and only see applications that meet the bar, with the AI's notes attached.
The point: cut the wasted time on both sides. Applicants stop blasting unfit roles; recruiters stop sifting through unqualified resumes.

Why this exists

Built end-to-end as a personal full-stack project to learn the MERN stack with strict architectural separation (MVC) and to integrate an LLM (Gemini) behind a swappable adapter rather than calling the SDK from controllers.

Stack

Layer Choice Frontend React 18 Backend Node.js + Express Database MongoDB (via Mongoose) Auth JWT AI Google Gemini API (behind an adapter) Tests Jest + Supertest

Architecture

Strict three-layer Model-View-Controller:
Model — Mongoose models in /backend/models/ define the shape and validators. No business logic.
View — React components in /frontend/src/components/ are presentation only. No data fetching or business logic.
Controller — Express controllers in /backend/controllers/ hold all business logic. Each controller is responsible for one resource (Users, Jobs, Applications, AI).
The Gemini integration sits behind a thin adapter (/backend/ai/) so the model provider can be swapped without touching controller code or the React app.

Key engineering decisions

MVC separation as a hard rule. No business logic in React; no presentation logic in controllers. This made the test surface easy to define — every business rule has a controller test, not a UI test.
AI behind an adapter. The Gemini call lives in one place. Want to A/B test against another model? Replace one file. The controller and the UI never know.
Recruiter-set criteria as filters, not blockers. Applicants still see jobs they don't quite fit (so they can grow into them) — the AI just tells them so up front. Only submission requires meeting the bar.
JWT auth with httpOnly refresh tokens. Standard separation; refresh tokens stored httpOnly to mitigate XSS exfiltration.

Setup

Prerequisites

Node.js 22+
MongoDB 7+
Google Gemini API key

Configure

Create .env files in /backend and /frontend:


Run


Test


Screenshots

Landing
Applicant dashboard
Recruiter dashboard
Recruiter applicant view

Project structure


Contribution

Branching strategy: dev is the integration branch; feature branches branch from dev, named by ticket number. PRs go to dev, require one peer review, and dev merges to main at sprint boundaries.

Code style

React components live under /frontend/src/components/<kebab-case>/ with a CamelCase JS + matching CSS file (e.g. ApplicantDashboard.js + ApplicantDashboard.css).
Express controllers live under /backend/controllers/ with CamelCase filenames (e.g. UserController.js).
No business logic in React components; no presentation in controllers.

License

Personal portfolio project.
Like this project

Posted Aug 8, 2026

Built a two-sided MERN job board where Gemini gives applicants fit feedback before submission and recruiters review candidates against defined criteria.