Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Affan's Portfolio — Spring Boot Web Application

A professional portfolio website built with Java 17, Spring Boot 3, Thymeleaf, Maven, and a full Jenkins CI/CD pipeline. Features a contact form backed by a REST API and H2 database, optional Docker support, and a responsive editorial-dark UI.


Table of Contents

  1. Tech Stack
  2. Project Structure
  3. Prerequisites
  4. Running Locally (Maven)
  5. Running with Docker
  6. Jenkins CI/CD Setup
  7. API Reference
  8. Customisation
  9. Deployment Notes

Tech Stack

Layer Technology
Backend Java 17, Spring Boot 3.2, Spring MVC
Templating Thymeleaf 3
Persistence Spring Data JPA, H2 (in-memory)
Build Apache Maven 3.9
CI/CD Jenkins (Declarative Pipeline)
Container Docker (multi-stage), Docker Compose
Frontend Vanilla HTML/CSS/JS (no framework)
Monitoring Spring Actuator (/actuator/health)

Project Structure

portfolio/
├── src/
│   ├── main/
│   │   ├── java/com/affan/portfolio/
│   │   │   ├── PortfolioApplication.java      # Entry point
│   │   │   ├── config/
│   │   │   │   └── WebConfig.java             # CORS, resource handlers
│   │   │   ├── controller/
│   │   │   │   ├── HomeController.java        # Renders index.html
│   │   │   │   └── ContactController.java     # REST API /api/contact
│   │   │   ├── model/
│   │   │   │   ├── ContactMessage.java        # JPA entity
│   │   │   │   └── ContactMessageRepository.java
│   │   │   └── service/
│   │   │       └── ContactService.java        # Business logic
│   │   └── resources/
│   │       ├── templates/
│   │       │   └── index.html                 # Thymeleaf template
│   │       ├── static/
│   │       │   ├── css/style.css
│   │       │   ├── js/main.js
│   │       │   └── images/                    # Add profile.jpg here
│   │       └── application.properties
│   └── test/
│       ├── java/com/affan/portfolio/
│       │   ├── PortfolioApplicationTests.java
│       │   └── controller/
│       │       └── ContactControllerTest.java
│       └── resources/
│           └── application-test.properties
├── Dockerfile
├── docker-compose.yml
├── Jenkinsfile
├── pom.xml
└── README.md

Prerequisites

Tool Version Notes
Java (JDK) 17+ java -version
Maven 3.9+ Or use included mvnw wrapper
Git Any For cloning and version control
Jenkins LTS For CI/CD pipeline
Docker 24+ Optional — for containerised runs
Docker Compose 2+ Optional — bundled with Docker Desktop

Running Locally (Maven)

1. Clone the Repository

git clone https://github.com/<your-username>/portfolio.git
cd portfolio

2. Build and Run

# Using Maven wrapper (no Maven install needed)
./mvnw spring-boot:run

# Or with system Maven
mvn spring-boot:run

3. Open in Browser

http://localhost:8080

4. Run Tests

./mvnw test

5. Build Runnable JAR

./mvnw clean package -DskipTests
java -jar target/portfolio.jar

Running with Docker

Build and start with Docker Compose

docker compose up --build

Or manually with Docker

# Build
docker build -t affan-portfolio .

# Run
docker run -p 8080:8080 affan-portfolio

Check health

curl http://localhost:8080/actuator/health

Jenkins CI/CD Setup

The included Jenkinsfile defines a 5-stage declarative pipeline:

Checkout → Build → Test → Package → Deploy

Step 1 — Install Jenkins

# macOS (Homebrew)
brew install jenkins-lts
brew services start jenkins-lts

# Linux (Ubuntu/Debian)
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo apt-key add -
sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt update && sudo apt install jenkins
sudo systemctl start jenkins

Open Jenkins at http://localhost:8080 (note: if the portfolio app is already on 8080, run Jenkins on a different port by editing /etc/default/jenkins or the Homebrew plist — change HTTP_PORT to 8090).

Step 2 — Configure Tools in Jenkins

Go to Manage Jenkins → Global Tool Configuration and add:

Tool Name Version
JDK JDK-17 Java 17
Maven Maven-3.9 Maven 3.9.x

The names must match exactly what's in the Jenkinsfile.

Step 3 — Create a Pipeline Job

  1. Click New Item → name it portfolio → select Pipeline → OK.
  2. Under Pipeline, set Definition to Pipeline script from SCM.
  3. Set SCM to Git and enter your repository URL.
  4. Set Script Path to Jenkinsfile.
  5. Save.

Step 4 — Connect GitHub via Webhook (Recommended)

  1. In Jenkins job → Build Triggers → tick GitHub hook trigger for GITScm polling.
  2. In GitHub repo → Settings → Webhooks → Add webhook:
    • Payload URL: http://<your-jenkins-host>:8090/github-webhook/
    • Content type: application/json
    • Events: Just the push event

Every push to GitHub will now automatically trigger the pipeline.

Step 5 — Create Deployment Directory

sudo mkdir -p /opt/portfolio
sudo chown $(whoami):$(whoami) /opt/portfolio

Pipeline Stages

Stage What it does
Checkout Pulls the latest code from GitHub
Build mvn clean compile — compiles all sources
Test mvn test — runs unit and integration tests
Package mvn package — produces target/portfolio.jar
Deploy Stops old instance, copies JAR, starts new one, waits for health check

API Reference

POST /api/contact

Submit a contact form message.

Request body (JSON):

{
  "name":    "Jane Doe",
  "email":   "jane@example.com",
  "subject": "Internship Opportunity",
  "message": "Hi Affan, I came across your portfolio and would love to connect!"
}

Success response (200):

{
  "success": true,
  "message": "Thank you, Jane Doe! Your message has been received.",
  "id": 1
}

Validation error (400):

{
  "success": false,
  "errors": {
    "email": "Please provide a valid email address"
  }
}

GET /api/contact/stats

Returns message count statistics.

{
  "totalMessages": 5,
  "unreadMessages": 3
}

GET /api/contact/messages

Returns all stored contact messages (protect in production).


PATCH /api/contact/{id}/read

Marks a specific message as read.


GET /actuator/health

Spring Actuator health endpoint — used by Jenkins deploy health check.

{
  "status": "UP"
}

H2 Console (development only)

http://localhost:8080/h2-console
JDBC URL: jdbc:h2:mem:portfoliodb
Username: sa
Password: (empty)

Customisation

Add Your Profile Photo

  1. Place profile.jpg in src/main/resources/static/images/.
  2. In index.html, replace the placeholder block:
<!-- REMOVE this block: -->
<div class="hero__photo-initials">A</div>

<!-- ADD this instead: -->
<img th:src="@{/images/profile.jpg}" alt="Affan" class="hero__photo-img"/>

Update Personal Details

Edit HomeController.java to change:

  • Skills and proficiency levels
  • Project titles, descriptions, links, and tech stacks
  • Any model attributes passed to the template

Edit index.html to update:

  • Contact email and social links in the Contact section
  • Footer text

Connect a Real Database (Production)

Replace H2 with MySQL or PostgreSQL in pom.xml and application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/portfoliodb
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update

Deployment Notes

  • The app binds to http://localhost:8080 by default.
  • The Deploy stage in the Jenkins pipeline:
    • Reads the PID from /opt/portfolio/portfolio.pid
    • Gracefully stops the old process
    • Copies the new JAR to /opt/portfolio/
    • Starts the app and waits up to 30 seconds for the health check to pass
  • Logs are written to /opt/portfolio/portfolio.log
  • For internet-facing deployment, put Nginx as a reverse proxy in front of port 8080.

Built by Affan — CS & Business Systems Engineer

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages