A full-stack job portal built on a microservice architecture, where job seekers can discover jobs, apply, analyse their resume with AI, and subscribe for premium features — while recruiters manage companies, post jobs, and track applications.
┌──────────────────┐
│ Next.js Frontend │
└────────┬─────────┘
│ HTTP (Axios)
┌──────────────────┼──────────────────┐
│ │ │
┌──────▼──────┐ ┌───────▼──────┐ ┌──────▼──────┐
│ Auth Service │ │ Job Service │ │User Service │
│ (Node.js) │ │ (Node.js) │ │ (Node.js) │
└──────┬───────┘ └───────┬───────┘ └──────┬──────┘
│ │ │
┌──────▼───────────────────▼───────────────────▼──────┐
│ PostgreSQL (Neon) │
└──────────────────────────────────────────────────────┘
│
┌──────▼──────┐ ┌──────────────────┐
│Payment Svc │ │ Utils Service │
│ (Razorpay) │ │ Cloudinary Upload │
└─────────────┘ │ Gemini AI (Resume)│
│ Kafka Consumer │
┌─────────────┐ └──────────────────┘
│ Redis Cache │◄── Token blacklist / OTP TTL
└─────────────┘
▲
┌──────┴──────┐
│Apache Kafka │◄── Async email delivery (forgot-password, alerts)
└─────────────┘
Each service is independently Dockerized and communicates over HTTP and Kafka topics.
| Service | Port | Responsibility |
|---|---|---|
auth |
5000 | Register, Login, JWT, Forgot/Reset Password |
user |
5001 | Profile management, Skills, Resume upload |
job |
5002 | Companies, Job listings, Applications |
payment |
5003 | Razorpay checkout & webhook verification |
utils |
5004 | Cloudinary uploads, Gemini AI, Kafka mail consumer |
frontend |
3000 | Next.js 16 UI |
Backend
- Node.js + Express + TypeScript
- PostgreSQL (via Neon serverless) with raw
postgresdriver - Redis — password-reset token TTL, caching
- Apache Kafka (KafkaJS) — async email delivery pipeline
- JWT (15-day auth tokens, 15-min reset tokens)
- Bcrypt password hashing
- Cloudinary — resume & profile picture storage
- Razorpay — subscription payments (₹119/month)
- Nodemailer — transactional email (SMTP via Gmail)
- Google Gemini 2.5 Flash — AI resume analyser + career guide
- Docker + Dockerfile per service
Frontend
- Next.js 16 (App Router) + React 19 + TypeScript
- Tailwind CSS v4 + shadcn/ui (Radix primitives)
- next-themes (dark/light mode)
- Axios + react-hot-toast
- Role-based auth — Separate flows for
jobseekerandrecruiteron registration - Resume upload at registration — PDF stored on Cloudinary, public_id tracked for replacement
- Forgot Password flow — JWT reset token stored in Redis with 15-min TTL, delivered via Kafka → Nodemailer
- Job & Company management — Recruiters create companies, post jobs, update application status
- Application tracking — Job seekers see applied jobs; recruiters see all applicants per job
- Subscription gating — Razorpay payment creates a 30-day subscription window in the DB; HMAC-SHA256 signature verification
- AI Resume Analyser — Gemini 2.5 Flash reads uploaded PDF, returns ATS score breakdown + actionable suggestions
- AI Career Guide — Gemini generates personalised job role suggestions and learning roadmap from user's skill set
- Cloudinary util service — Centralised upload/replace endpoint called by other services internally
- Node.js ≥ 18
- Docker & Docker Compose
- A running Kafka broker (see
kafka setup guide.pdfin the repo root) - Accounts for: Neon PostgreSQL, Cloudinary, Razorpay, Google AI Studio (Gemini), Gmail SMTP
Each service has its own .env. Key variables:
auth service
DATABASE_URL=
JWT_SEC=
UPLOAD_SERVICE=http://localhost:5004 # utils service URL
Frontend_Url=http://localhost:3000
Kafka_Broker=localhost:9092
REDIS_URL=payment service
DATABASE_URL=
JWT_SEC=
Razorpay_Key=
Razorpay_Secret=utils service
CLOUDINARY_CLOUD_NAME=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
API_KEY_GEMINI=
Kafka_Broker=localhost:9092
SMTP_USER=
SMTP_PASS=# Build and start all services
docker compose up --build
# Or run a single service
cd services/auth
docker build -t auth-service .
docker run --env-file .env -p 5000:5000 auth-servicecd services/auth
npm install
npm run devRepeat for each service. Start the frontend:
cd frontend
npm install
npm run dev| Method | Route | Description |
|---|---|---|
| POST | /register |
Register jobseeker (with resume) or recruiter |
| POST | /login |
Login, returns JWT |
| POST | /forgot |
Send password reset email via Kafka |
| POST | /reset/:token |
Reset password with Redis-validated token |
| Method | Route | Description |
|---|---|---|
| POST | /new |
Create job listing (recruiter) |
| GET | /all |
List all active jobs |
| GET | /:jobId |
Job details |
| POST | /company/new |
Create company |
| GET | /application/:jobId |
Get all applicants for a job |
| PUT | /application/update/:id |
Update application status |
| Method | Route | Description |
|---|---|---|
| POST | /checkout |
Create Razorpay order |
| POST | /verify |
Verify payment signature & activate subscription |
| Method | Route | Description |
|---|---|---|
| POST | /upload |
Upload/replace file on Cloudinary |
| POST | /resume-analyser |
ATS score + suggestions via Gemini |
| POST | /career |
Career path suggestions via Gemini |
job-portal/
├── frontend/ # Next.js app
│ └── src/
│ ├── app/ # App Router pages
│ └── components/ # Shared UI components
├── services/
│ ├── auth/ # Authentication microservice
│ ├── job/ # Job & company microservice
│ ├── user/ # User profile microservice
│ ├── payment/ # Payment microservice
│ └── utils/ # Upload, AI, email microservice
├── kafka setup guide.pdf
└── resume analyser and about.pdf
- Kafka for emails — Decouples the auth service from SMTP failures; forgot-password emails are fire-and-forget from the auth service perspective.
- Redis for reset tokens — Prevents token reuse after password change without a full DB lookup; TTL auto-cleans expired tokens.
- Centralised utils service — Cloudinary credentials live in one service only; other services call it over HTTP, keeping secrets isolated.
- Raw SQL over ORM — Uses the
postgres(tagged template) driver directly for predictable query behaviour without ORM abstraction overhead.
MIT