Skip to content

Latest commit

Β 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧳 JobPortal API

A production-ready RESTful Job Search API built with Spring Boot 3, PostgreSQL, Redis, and Docker. Features JWT authentication, role-based access control, rate limiting, token blacklisting, and full Swagger documentation.

✨ Features

  • βœ… JWT-based stateless authentication
  • βœ… Role-based access control (ROLE_USER, ROLE_ADMIN)
  • βœ… Job search with multi-filter support (keyword, location, job type)
  • βœ… JPA Specifications for dynamic query building
  • βœ… Pagination & sorting with validated bounds
  • βœ… Rate limiting per IP (5 requests/minute)
  • βœ… Redis-backed token blacklist with logout support
  • βœ… Structured error responses on all endpoints
  • βœ… Swagger / OpenAPI 3 documentation with Bearer auth
  • βœ… Multi-stage Dockerfile for optimized image size
  • βœ… All secrets managed via environment variables

πŸ›  Tech Stack

Layer Technology
Language Java 17
Framework Spring Boot 3.3.4
Security Spring Security 6 + JWT (jjwt 0.11.5)
Database PostgreSQL 15
Cache / Session Redis (Lettuce)
ORM Hibernate / Spring Data JPA
Mapping MapStruct
Validation Jakarta Bean Validation
Rate Limiting Bucket4j
Documentation SpringDoc OpenAPI (Swagger UI)
Containerization Docker + Docker Compose
Build Tool Maven

πŸ— Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Client / Swagger UI            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚   RateLimitFilter  β”‚  (Bucket4j, per IP)
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚ JwtAuthentication  β”‚  (Token validation + Blacklist check)
              β”‚      Filter        β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚        Controllers         β”‚
          β”‚  AuthController            β”‚
          β”‚  JobController             β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚         Services           β”‚
          β”‚  AuthService               β”‚
          β”‚  JobServiceImpl            β”‚
          β”‚  TokenBlacklistService     β”‚
          β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                 β”‚          β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”  β”Œβ”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚ PostgreSQL  β”‚  β”‚   Redis    β”‚
        β”‚  (JPA)      β”‚  β”‚ (Blacklist)β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Getting Started

Prerequisites

  • Docker & Docker Compose
  • Java 17+ (only if running locally without Docker)

Run with Docker (Recommended)

1. Clone the repository:

git clone https://github.com/your-username/jobportal-api.git
cd jobportal-api

2. Create a .env file in the project root:

DB_USERNAME=postgres
DB_PASSWORD=yourpassword
JWT_SECRET_KEY=404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
JWT_EXPIRATION=86400000
REDIS_HOST=redis
REDIS_PORT=6379

3. Build and start all services:

docker compose up --build

4. Open Swagger UI:

http://localhost:8080/swagger-ui/index.html

Run Locally (Without Docker)

1. Start PostgreSQL and Redis locally, then set environment variables:

export DB_USERNAME=postgres
export DB_PASSWORD=yourpassword
export JWT_SECRET_KEY=404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
export JWT_EXPIRATION=86400000
export REDIS_HOST=localhost
export REDIS_PORT=6379

2. Run the application:

./mvnw spring-boot:run

πŸ” Environment Variables

Variable Description Example
DB_USERNAME PostgreSQL username postgres
DB_PASSWORD PostgreSQL password secret
JWT_SECRET_KEY Base64-encoded HMAC secret (min 256-bit) 404E63...
JWT_EXPIRATION Token expiry in milliseconds 86400000 (24h)
REDIS_HOST Redis hostname redis (Docker) / localhost
REDIS_PORT Redis port 6379

⚠️ Never commit the .env file to version control. It is listed in .gitignore.


πŸ“‘ API Endpoints

Auth

Method Endpoint Access Description
POST /api/v1/auth/register Public Register a new user
POST /api/v1/auth/login Public Login and receive JWT token
POST /api/v1/auth/logout Authenticated Invalidate current token

Jobs

Method Endpoint Access Description
GET /api/v1/jobs/search Public Search jobs with filters
POST /api/v1/jobs/create ROLE_ADMIN Create a new job listing

Search Query Parameters

Parameter Type Default Description
keyword String β€” Search in title and description
location String β€” Filter by location
jobType Enum β€” FULL_TIME, PART_TIME, REMOTE, CONTRACT
page Integer 0 Page number (min: 0)
size Integer 10 Page size (min: 1, max: 100)
sortBy String createdAt createdAt, salary, title, companyName

πŸ”‘ Authentication Flow

1. POST /api/v1/auth/register  β†’  201 Created  +  JWT token
2. POST /api/v1/auth/login     β†’  200 OK        +  JWT token
3. Use token in header:  Authorization: Bearer <token>
4. POST /api/v1/auth/logout    β†’  204 No Content (token blacklisted in Redis)

Register request body:

{
  "firstname": "John",
  "lastname": "Doe",
  "email": "john@example.com",
  "password": "secret123"
}

Login request body:

{
  "email": "john@example.com",
  "password": "secret123"
}

Response:

{
  "accessToken": "eyJhbGci...",
  "tokenType": "Bearer"
}

⚑ Rate Limiting

Requests are rate-limited per IP address using Bucket4j:

  • Limit: 5 requests per minute
  • Scope: All endpoints except /api/v1/auth/** and Swagger UI
  • Exceeded response: 429 Too Many Requests

πŸ›‘ Security

Feature Implementation
Password hashing BCrypt
Token format JWT (HS256)
Session policy Stateless
Token revocation Redis blacklist (TTL = token expiry)
Role enforcement @PreAuthorize + @EnableMethodSecurity
CORS Configurable origin allowlist
Secret management Environment variables only β€” no hardcoded credentials

πŸ“ Project Structure

src/main/java/com/example/
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ AppConfig.java              # AuthProvider, PasswordEncoder, Swagger config
β”‚   └── DataInitializer.java        # Seeds ROLE_USER and ROLE_ADMIN on startup
β”œβ”€β”€ controller/
β”‚   β”œβ”€β”€ AuthController.java         # Register, Login, Logout
β”‚   └── JobController.java          # Search, Create
β”œβ”€β”€ dto/
β”‚   β”œβ”€β”€ AuthResponse.java
β”‚   β”œβ”€β”€ JobCreateDto.java
β”‚   β”œβ”€β”€ JobResponseDto.java
β”‚   β”œβ”€β”€ JobSearchRequestDto.java
β”‚   β”œβ”€β”€ LoginRequest.java
β”‚   └── RegisterRequest.java
β”œβ”€β”€ entity/
β”‚   β”œβ”€β”€ Job.java
β”‚   β”œβ”€β”€ Role.java
β”‚   └── User.java
β”œβ”€β”€ enums/
β”‚   β”œβ”€β”€ JobType.java
β”‚   └── RoleType.java
β”œβ”€β”€ exception/
β”‚   β”œβ”€β”€ ErrorDetails.java
β”‚   β”œβ”€β”€ GlobalExceptionHandler.java
β”‚   β”œβ”€β”€ ResourceNotFoundException.java
β”‚   └── UserNotFoundException.java
β”œβ”€β”€ filter/
β”‚   └── RateLimitFilter.java        # Bucket4j IP-based rate limiting
β”œβ”€β”€ mapper/
β”‚   └── JobMapper.java              # MapStruct mapper
β”œβ”€β”€ repository/
β”‚   β”œβ”€β”€ JobRepository.java
β”‚   β”œβ”€β”€ RoleRepository.java
β”‚   β”œβ”€β”€ UserRepository.java
β”‚   └── specification/
β”‚       └── JobSpecification.java   # Dynamic JPA Specifications
β”œβ”€β”€ security/
β”‚   β”œβ”€β”€ CustomUserDetailsService.java
β”‚   β”œβ”€β”€ JwtAuthenticationFilter.java
β”‚   β”œβ”€β”€ JwtService.java
β”‚   └── SecurityConfig.java
└── service/
    β”œβ”€β”€ AuthService.java
    β”œβ”€β”€ JobService.java             # Interface
    β”œβ”€β”€ TokenBlacklistService.java  # Redis-backed token blacklist
    └── impls/
        └── JobServiceImpl.java

πŸ“„ License

This project is for educational purposes.

About

A production-ready RESTful Job Search API built with Spring Boot 3, PostgreSQL, Redis, and Docker. Features JWT authentication, role-based access control, rate limiting, token blacklisting, and full Swagger documentation

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages