0% found this document useful (0 votes)
18 views48 pages

Smart Portfolio Builder Project Report

Summer Training Project

Uploaded by

Techaholic Hub
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views48 pages

Smart Portfolio Builder Project Report

Summer Training Project

Uploaded by

Techaholic Hub
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

A SUMMER TRAINING PROJECT REPORT

ON

“Smart Portfolio Builder Platform”

A Summer Internship Project Report Submitted in Partial Fulfilment of the Requirements for
the Degree of Bachelor of Computer Applications (BCA)

Batch: 2023-2026

Under the Guidance of Submitted by-


RPWHIZ Gunjan Joshi
Enrollment No.: 70224002023

Department of Computer Applications


Trinity Institute of Professional Studies, Dwarka
Guru Gobind Singh Indraprastha University, Delhi
CERTIFICATE:
DECLARATION

This is to certify that Report entitled “Smart Portfolio Builder Project” which is submitted by
me, in partial fulfilment of the requirement for the award of degree of Bachelor of Computer
Applications to GGSIP University, Dwarka, Delhi, comprise only my original work carried
out during my internship under RPWHIZ. The project work has not been submitted elsewhere
for any degree or diploma. Due acknowledgement has been made in the text to all other
material used.

Date: 02.11.25 Approved By:


Signature:
Gunjan Joshi
ACKNOWLEDGEMENT

I wish to express my sincere gratitude to all those with whom I worked and whose thoughts
and inspection contributed towards the completion of this project. This project would not
have started and much less completed without the encouragement and support of my faculty
guide, without whose valuable insights the project would not have seen daylight. Finally, I
would also like thank to all my dear friends for their kind cooperation, advice and
encouragement during the long and arduous task of preparing this report and carrying out the
project. At last, but not the least, I would like to acknowledge my dear family members
whose blessings, inspiration and encouragement have resulted in the successful completion of
the project.

Gunjan Joshi
BCA- V Sem
TABLE OF CONTENT

[Link] TOPIC Page No.

1. Abstraction 6

2. Chapter 1- Problem Formulation 7

3. Chapter 2- System Analysis 8 - 10

4. Chapter 3- System Design 11 - 41

5. Chapter 4- Testing & Implementation 43 – 45

6. Chapter 5- Conclusions & References 46

7. Chapter 6- Annexures 47
ABSTRACT

The Smart Portfolio Builder is a beginner-friendly website that allows users to create, preview,
and download a personalized portfolio using a simple and aesthetic interface. With intuitive form
inputs and theme customization, users can generate a professional online profile without needing
any coding knowledge.
This project is built using HTML, CSS, Nodejs, MongoDB and JavaScript, making it
accessible, light, and entirely browser based
CHAPTER- 1
PROBLEM FORMULATION

1. Problem Statement
In today’s competitive professional world, having a well-structured and visually appealing
portfolio is essential for students, freelancers, and professionals to showcase their skills,
education, and experience.

However, most individuals lack the technical expertise or time to design their own portfolio
websites from scratch. Manually coding and designing a personal portfolio can be tedious,
especially for beginners who are not proficient in web development.

To address this challenge, the Smart Portfolio Builder project aims to provide an automated
and user-friendly platform where users can input their personal and professional details
through a simple form, and the system dynamically generates a professional, aesthetically
pleasing, and responsive portfolio webpage based on their inputs.

2. Objectives
The main objectives of this project are:
1. To design and develop a web-based system that allows users to create personalized
portfolios easily.
2. To enable users to input their personal information, educational background, skills,
projects, and contact details through an interactive form.
3. To store user details locally (or later on a database) for previewing or regenerating the
portfolio.
4. To automatically generate a responsive, modern, and aesthetic portfolio layout using the
provided data.
5. To allow users to download or preview their generated portfolio for sharing or hosting
purposes.
6. To create a minimalistic and user-friendly interface suitable for non-technical users.

3. Scope
• Developing a front-end web interface using HTML, CSS, and JavaScript.
• Designing a form-based input system where users can enter their details.
• Implementing local storage functionality to temporarily store and retrieve user data.
• Providing an option to preview or download the generated portfolio in a predesigned
layout.
• Designing the UI to be aesthetic, responsive, and minimalistic, with a focus on
accessibility and ease of use
• To allow users to download or preview their generated portfolio for sharing or
hosting purposes.
CHAPTER- 2
SYSTEM ANALYSIS

This chapter covers requirement analysis, feasibility study, and system objectives for
Portfolio Builder

Functional Requirements:
Tech Stack & Versions

Tools Versions Description


HTML HTML5 The core markup language used to structure and present
content on the web. It provides semantic tags like
<header>, <section>, and <footer> that make websites
more accessible and SEO-friendly.
CSS CSS3 Used for styling and layout. CSS3 includes powerful tools like
Flexbox, Grid, transitions, and animations to create
responsive and visually appealing designs.
JavaScript ES6 The programming language that adds interactivity and logic
to websites. ES6 introduces features like arrow functions,
template literals, let/const, and modules for cleaner and
more efficient code.
Local Storage Built-in A browser-based storage mechanism that allows data (like
API form inputs) to be saved locally on a user’s device without
needing a database or server.
jsPDF v.2.5.1 A JavaScript library used to generate downloadable PDF
documents directly from web pages. It’s ideal for creating
printable resumes, portfolios, and reports.
Node js V20.x LTS A powerful JavaScript runtime built on Chrome’s V8 engine.
It allows developers to run JavaScript on the server side and
build scalable backend services and APIs.
MongoDB V7.0.x A NoSQL database that stores data in a flexible, JSON-like
format called BSON. It’s known for its scalability, speed, and
compatibility with [Link] applications.
Visual Studio V1.95 A lightweight and highly customizable code editor developed
Code by Microsoft. It supports extensions for HTML, CSS,
JavaScript, [Link], Git, and debugging tools.
Google Chrome V140+ A modern web browser with advanced developer tools that
help test, debug, and optimize web applications efficiently.

Folder Structure-
SmartPortfolioBuilder/

├── [Link] # Main landing page (intro, features, CTA)
├── [Link] # Portfolio creation form page

├── css/
│ ├── [Link] # Global and landing page styles
│ ├── [Link] # Form page styles (white card with curved edges)
│ └── [Link] # (Optional) For mobile/tablet responsiveness

├── js/
│ ├── [Link] # Handles theme switching, animations, and events
│ ├── [Link] # Handles form input + Local Storage saving
│ └── [Link] # jsPDF logic for portfolio download

├── images/
│ ├── [Link] # Website logo
│ ├── [Link] # Decorative or profile icon for landing
│ ├── [Link] # Background aesthetic illustration
│ └── [Link] # (Optional) Browser tab icon

├── assets/
│ ├── fonts/ # Custom typography (e.g., Playfair Display, Poppins)
│ └── icons/ # Small decorative icons (LinkedIn, GitHub, etc.)

└── [Link] # Project overview (setup steps + feature list)
CHAPTER- 3
SYSTEM DESIGN

The SmartPortfolioBuilder is a web-based application designed to help users easily create,


preview, and download personalized portfolio websites. The system uses client-side
technologies to ensure simplicity, speed, and offline functionality without requiring a backend
server.

The project follows a client-side architecture (also known as front-end architecture) where all
operations — form handling, data storage, and PDF generation — are executed within the browser.

CODE-
FRONTEND
[Link]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Smart Portfolio Builder | Home</title>
<link rel="stylesheet" href="[Link]">
<link href="[Link]
rel="stylesheet">
</head>

<body>
<!-- Header -->
<header class="topbar">
<div class="top-left">
<img src="[Link]" alt="Logo" class="logo">
<nav class="top-nav">
<a href="#">Home</a>
<a href="[Link]">Create</a>
<a href="#">Contact Us</a>
</nav>
</div>

<div class="top-right">
<select class="theme-select">
<option value="theme" selected>Themes</option>
<option value="light"> Light</option>
<option value="dark"> Dark</option>
</select>
</select>
<img src="user [Link]" alt="User Icon" class="user-icon" onclick="openModal()">
</div>
</header>

<!-- Main Page -->


<section class="main-hero">
<div class="hero-left">
<h1>Want to Build a Portfolio?</h1>
<p>Get started with us now!</p>
<a href="#" class="btn" onclick="openModal()">Get Started</a>
</div>
<div class="hero-right">
<img src="main [Link]" alt="Portfolio Illustration">
</div>
</section>

<!-- Login/Signup -->


<div class="modal" id="authModal">
<div class="modal-content">
<span class="close-btn" onclick="closeModal()">&times;</span>
<h2 id="formTitle">Login</h2>

<form id="loginForm" onsubmit="loginUser(event)">


<input type="email" placeholder="E-mail" required>
<input type="password" placeholder="Password" required>
<a href="#" class="forgot">Forgot your password?</a>
<button type="submit">Login</button>
<p class="switch">Don't have an account? <a href="#" onclick="showSignup()">Sign
up</a></p>
</form>

<form id="signupForm" style="display: none;" onsubmit="signupUser(event)">


<input type="email" placeholder="E-mail" required>
<input type="password" placeholder="Password" required>
<input type="password" placeholder="Confirm Password" required>
<button type="submit">Sign Up</button>
<p class="switch">Already have an account? <a href="#"
onclick="showLogin()">Login</a></p>
</form>
</div>
</div>
<script src="[Link]"></script>
</body>
</html>

[Link]
/* Header */
.topbar {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #5c1212;
padding: 12px 40px;
color: white;
font-family: 'Poppins', sans-serif;
position: sticky;
top: 0;
z-index: 999;
}

/*Logo*/
.top-left {
display: flex;
align-items: center;
gap: 40px;
}

.logo {
height: 60px;
width: auto;
object-fit: contain;
}

.top-nav {
display: flex;
gap: 25px;
}

.top-nav a {
text-decoration: none;
color: white;
font-weight: 500;
font-size: 1rem;
transition: opacity 0.2s ease-in-out;
}
.top-nav a:hover {
opacity: 0.8;
}

.top-right {
display: flex;
align-items: center;
gap: 15px;
}

.theme-select {
padding: 6px 10px;
font-size: 0.9rem;
border-radius: 5px;
border: none;
background-color: #f7f7f7;
color: #5c1212;
font-family: 'Poppins', sans-serif;
outline: none;
cursor: pointer;
}

.user-icon {
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
}

*{
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: 'Poppins', sans-serif;
background-color: #fdf6ef;
}

/* Main Page */
.main-hero {
display: flex;
justify-content: space-between;
align-items: center;
padding: 80px 100px;
min-height: 100vh;
background-color: #fff3e5;
gap: 30px;
}

.hero-left {
flex: 1;
max-width: 550px;
color: #5c1212;
}

.hero-left h1 {
font-size: 3.8rem;
font-weight: 700;
margin-bottom: 20px;
color: #5c1212;
}

.hero-left p {
font-size: 1.5rem;
font-weight: 500;
margin-bottom: 35px;
color: #4b2b38;
}

.hero-right {
flex: 1;
display: flex;
justify-content: flex-end;
align-items: center;
}

.hero-right img {
max-width: 100%;
width: 550px;
object-fit: contain;
background-color: transparent;
filter: drop-shadow(0 5px 20px rgba(0, 0, 0, 0.1));
}
.btn {
padding: 14px 28px;
background-color: #5c1212;
color: #fff;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
font-size: 1.1rem;
transition: background-color 0.3s ease;
}

[Link]:hover {
background-color:#5c2222;
}

.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
justify-content: center;
align-items: center;
z-index: 9999;
}

.modal-content {
background-color: #fff;
padding: 30px;
width: 350px;
border-radius: 12px;
text-align: center;
position: relative;
animation: fadeIn 0.3s ease-in-out;
}

.modal-content h2 {
font-size: 2rem;
margin-bottom: 20px;
color: #5c1212;
}
.modal-content input {
display: block;
width: 100%;
margin-bottom: 15px;
padding: 12px;
border-radius: 8px;
border: 1px solid #ddd;
font-size: 1rem;
font-family: 'Poppins', sans-serif;
}

.modal-content .forgot {
font-size: 0.85rem;
color: #5c1212;
text-decoration: underline;
display: block;
margin-bottom: 20px;
}

.modal-content button {
width: 100%;
padding: 12px;
border: none;
background-color: #5c1212;
color: white;
font-weight: bold;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
}

.modal-content .switch {
margin-top: 15px;
font-size: 0.9rem;
}

.close-btn {
position: absolute;
right: 15px;
top: 15px;
font-size: 1.5rem;
cursor: pointer;
color: #999;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}

/* Portfolio Form*/
.form-section {
max-width: 800px;
margin: 80px auto;
padding: 40px;
background-color: #fff3e5;
border-radius: 12px;
box-shadow: 0 0 15px rgba(0,0,0,0.05);
}

.form-section h1 {
text-align: center;
color: #5c1212;
font-size: 2.5rem;
margin-bottom: 30px;
}

.portfolio-form {
display: flex;
flex-direction: column;
gap: 20px;
}

.portfolio-form label {
font-weight: 600;
font-size: 1.1rem;
color: #3b0a08;
}

.portfolio-form input,
.portfolio-form textarea {
padding: 12px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 1rem;
font-family: 'Poppins', sans-serif;
}
.portfolio-form textarea {
resize: vertical;
min-height: 100px;
}

.portfolio-form button {
background-color: #5c1212;
color: #fff;
padding: 14px;
font-weight: 600;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: background 0.3s ease;
}

.portfolio-form button:hover {
background-color: #833752;
}

.form-body {
background-color: #fff3e5;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}

.form-container {
background-color: #fff;
padding: 40px 50px;
border-radius: 16px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.05);
width: 100%;
max-width: 700px;
}

.form-heading {
text-align: center;
color: #5c1212;
font-size: 2rem;
margin-bottom: 30px;
}
.portfolio-form {
display: flex;
flex-direction: column;
gap: 20px;
}

.portfolio-form label {
font-weight: 600;
font-size: 1.1rem;
color: #3b0a08;
}

.portfolio-form input,
.portfolio-form textarea {
padding: 12px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 1rem;
font-family: 'Poppins', sans-serif;
}

.portfolio-form textarea {
resize: vertical;
min-height: 100px;
}

.portfolio-form button {
background-color: #5c1212;
color: #fff;
padding: 14px;
font-weight: 600;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: background 0.3s ease;
}

.portfolio-form button:hover {
background-color: #5c1212;
}
/* Base layout */
body {
margin: 0;
font-family: 'Segoe UI', sans-serif;
transition: all 0.3s ease;
}

.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 24px;
}

.nav-links {
list-style: none;
display: flex;
gap: 20px;
padding: 0;
margin: 0;
}

.nav-links a {
text-decoration: none;
font-weight: 500;
}

.actions {
display: flex;
align-items: center;
gap: 10px;
}

.main-content {
padding: 50px;
text-align: left;
}

.light-theme {
background-color: #fff7ef;
color: #400202;
}

.light-theme .navbar {
background-color: #661919;
color: white;
}

.light-theme .nav-links a,
.light-theme .user-icon {
color: white;
}

.light-theme select {
padding: 6px;
border: none;
border-radius: 4px;
background-color: #fff;
color: #000;
}

/* Dark Theme */
.dark-theme {
background-color: #121212;
color: #f1f1f1;
}

.dark-theme .navbar {
background-color: #1e1e1e;
color: #f1f1f1;
}

.dark-theme .nav-links a,
.dark-theme .user-icon {
color: #f1f1f1;
}

.dark-theme select {
padding: 6px;
border: none;
border-radius: 4px;
background-color: #2c2c2c;
color: #f1f1f1;
}

.cta-button {
margin-top: 16px;
padding: 10px 20px;
font-weight: bold;
border: none;
background-color: #7e1e1e;
color: white;
border-radius: 6px;
cursor: pointer;
}

[Link]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Create Portfolio | Smart Portfolio Builder</title>
<link rel="stylesheet" href="[Link]">
<link href="[Link]
rel="stylesheet">
</head>
<body>
<!-- Navigation Bar -->
<header class="topbar">
<div class="top-left">
<img src="[Link]" alt="Logo" class="logo">
<nav class="top-nav">
<a href="[Link]">Home</a>
<a href="[Link]">Create</a>
<a href="#">Contact Us</a>
</nav>
</div>

<div class="top-right">
<select class="theme-select">
<option value="theme" selected>Themes</option>
<option value="light"> Light</option>
<option value="dark"> Dark</option>
</select>
<img src="user [Link]" class="user-icon" onclick="openModal()">
</div>
</header>

<div class="form-body">
<div class="form-container">
<h1 class="form-heading">Create your portfolio</h1>
<form class="portfolio-form">

<label>Full Name</label>
<input type="text" placeholder="Enter your full name" required>

<label>Tell us about yourself</label>


<textarea placeholder="Write a brief bio..."></textarea>

<label>Educational Background</label>
<textarea placeholder="Mention your degree, university, and year..."></textarea>

<label>Work Experience</label>
<textarea placeholder="Share any internships, jobs, or freelance work you've
done..."></textarea>

<label>What are your core skills or areas of expertise?</label>


<input type="text" placeholder="e.g., Web Development, UI/UX, Python, etc." required>

<label>Projects (if any)</label>


<textarea placeholder="Mention project names, what they do, and tech used..."></textarea>

<label>Contact Information</label>
<input type="tel" placeholder="Phone number">
<input type="email" placeholder="Email address" required>
<input type="url" placeholder="LinkedIn or GitHub profile link">

<button type="submit">Save Details</button>


</form>
</div>
</div>

</body>
</html>

[Link]
body {
margin: 0;
font-family: 'Poppins', sans-serif;
background-color: #fde2c8;
}

.navbar {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #96384f;
padding: 10px 30px;
}

.logo {
height: 40px;
}

.nav-links {
list-style: none;
display: flex;
gap: 20px;
}

.nav-links li a {
color: white;
text-decoration: none;
font-weight: bold;
}

.right-nav {
display: flex;
align-items: center;
gap: 15px;
}

.theme-selector {
padding: 5px;
border-radius: 5px;
border: none;
}

.user-icon {
width: 30px;
height: 30px;
cursor: pointer;
}

.form-container {
background-color: white;
padding: 40px;
border-radius: 15px;
max-width: 700px;
margin: 40px auto;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

h2 {
text-align: center;
color: #6b1e1e;
margin-bottom: 30px;
}

form label {
display: block;
font-weight: bold;
margin-top: 15px;
color: #3c1e1e;
}

form input,
form textarea {
width: 100%;
padding: 10px;
font-size: 1em;
border-radius: 6px;
border: 1px solid #ccc;
margin-top: 5px;
}

form textarea {
resize: vertical;
}

.form-buttons {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 30px;
}

button {
padding: 10px 20px;
background-color: #6b1e1e;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 1em;
}

button:hover {
background-color: #581717;
}

[Link]

function openModal() {
[Link]('authModal').[Link] = 'flex';
}
function closeModal() {
[Link]('authModal').[Link] = 'none';
}
function showSignup() {
[Link]('loginForm').[Link] = 'none';
[Link]('signupForm').[Link] = 'block';
[Link]('formTitle').innerText = 'Sign Up';
}
function showLogin() {
[Link]('signupForm').[Link] = 'none';
[Link]('loginForm').[Link] = 'block';
[Link]('formTitle').innerText = 'Login';
}

//Sign Up
function signupUser(event) {
[Link]();

const email = [Link]('#signupForm input[type="email"]').value;


const password = [Link]('#signupForm input[type="password"]').value;

if ([Link](email)) {
alert("User already exists. Please login.");
showLogin();
} else {
[Link](email, password);
alert("Sign up successful! Please login.");
showLogin();
}
}
//Login
function loginUser(event) {
[Link]();

const email = [Link]('#loginForm input[type="email"]').value;


const password = [Link]('#loginForm input[type="password"]').value;

const storedPassword = [Link](email);

if (!storedPassword) {
alert("User not found. Please sign up first.");
showSignup();
} else if (storedPassword === password) {
alert("Login successful!");
closeModal();

// Optionally redirect
// [Link] = "[Link]";
} else {
alert("Incorrect password. Please try again.");
}
}
const themeSwitcher = [Link]("theme-switcher");
[Link]("change", function () {
const selectedTheme = [Link];
[Link]("light-theme", "dark-theme");
[Link](`${selectedTheme}-theme`);
});

BACKEND
UserModel
import mongoose from "mongoose";
const userschema = new [Link]({
name:{
type:String,
required:true
},
email:{
type:String,
required:true,
unique:true
},
password:{
type:String,
required:true
},
}
, {
timestamps:true
}
)
export default [Link]("user",userschema)

UserController
import User from "../models/[Link]"
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'

const generateToken =(userID)=>{


return [Link]({id:userID},[Link].JWT_SECRET,{expiresIn:"30d"})
}

export const registerUser = async (req,res) => {


try{
const {name,email,password} = [Link]
const userExists = await [Link]({email})
if(userExists){
return [Link](400).json({message:"user already exists"})
}
if([Link]<8){
return [Link](400).json({success:false,message:"password mut be alteast 8
characters"})
}
const salt = await [Link](10);
const hashedpassword = await [Link](password,salt)

const user = await [Link]({


name,
email,
password:hashedpassword
})
[Link](201).json({
_id:user._id,
name:[Link],
email:[Link],
token:generateToken(user._id)
})
}
catch(error){
[Link](500).json({
message:"server error",
error:[Link]
})
}

export const loginUser= async(req,res)=>{


try{
const {email,password} = [Link]
const user = await [Link]({email})
if(!user){
return [Link](500).json({message:"invalid email or password"})

}
const isMatch = await [Link](password,[Link])
if(!isMatch){
return [Link](500).json({message:"invaild email or password"})
}
[Link](201).json({
_id:user._id,
name:[Link],
email:[Link],
token:generateToken(user._id)
})
}
catch(error){
[Link](500).json({
message:"server error",
error:[Link]
})
}
}

export const getuserprofile = async (req,res) => {


try{
const user = await [Link]([Link]).select("-password")
if(!user){
return [Link](404).json({message:"user not found"})
}
[Link](user)
}
catch(error){
[Link](500).json({
message:"server error",
error:[Link]
})
}
}

UserRouter
import express from 'express'
import { loginUser, registerUser,getuserprofile} from '../controller/[Link]'
import { protect } from '../middleware/[Link]';
const userRouter = [Link]();

[Link]('/register',registerUser)
[Link]('/login',loginUser)
[Link]("/profile",protect,getuserprofile)
export default userRouter

ResumeModel
import mongoose from "mongoose";
const resumeSchema = new [Link] ({
userID:{
type:[Link],
ref:"user",
required :true
},
title:{
type:String,
required:true
},
thumbnaiLink:{
type:String
},
temmplate:{
type:String,
colorPalette : [String]
},
About_Yourself:{
type:String,
},

profileInfo:{
profilePreviewURL:String,
fullName:String,
designation:String,
summary:String
},
contactInfo:{
email:String,
phone:String,
location:String,
linkedin:String,
github:String,
website:String,
},
WorkExperience:[
{
company:String,
role:String,
startDate:String,
endDate:String,
description:String
},
],
education:[{
degree:String,
inistitution:String,
startDate:String,
endDate:String
},],
skiills:[{
name:String,
progress:String,
},],
projects:[{
title:String,
description:String,
github:String,
livedemo:String,
},],
certification:[{
title:String,
issuer:String,
year:String,
},],
languages:[{
name:String,
progress:Number
},],
interests:[String],
},
{
timestamps:{createdAt:"created at",updatedAt:"updated at"}
}
);
export default [Link]("resume",resumeSchema)

ResumeController
import Resume from '../models/[Link]'
import fs from 'fs'
import path from 'path';

export const createResume= async (req,res) => {


try{
const{title}=[Link];
const defaultResumeData = {
About_Yourself:{

},
profileInfo: {
profileImg: null,
previewUrl: '',
fullName: '',
designation: '',
summary: '',
},
contactInfo: {
email: '',
phone: '',
location: '',
linkedin: '',
github: '',
website: '',
},
workExperience: [
{
company: '',
role: '',
startDate: '',
endDate: '',
description: '',
},
],
education: [
{
degree: '',
institution: '',
startDate: '',
endDate: '',
},
],
skills: [
{
name: '',
progress: 0,
},
],
projects: [
{
title: '',
description: '',
github: '',
liveDemo: '',
},
],
certifications: [
{
title: '',
issuer: '',
year: '',
},
],
languages: [
{
name: '',
progress: '',
},
],
interests: [''],
};
const newwResume = await [Link]({
userID:[Link]._id,
title,
...defaultResumeData,
...[Link]
})
[Link](201).json(newwResume)
}
catch(error){
[Link](500).json({message:"failed to create resume",
error:[Link]})
}
}

export const getUserResume= async (req,res) => {


try{
const resume = await [Link]({userID:[Link]._id}).sort({
updateAt:-1
})
[Link](resume)
}
catch(error){
[Link](500).json({message:"failed to get resume",
error:[Link]})
}
}

export const getResumebyID = async (req,res) => {


try {
const resume = await [Link]({_id:[Link],userID:[Link]._id})
if(!resume){
return [Link](404).json({message:"resume not found"})
}
[Link](resume)
} catch (error) {
[Link](500).json({message:"failed to get resume",
error:[Link]})
}
}

export const updateResume = async (req,res) => {


try {
const resume = await [Link]({
_id:[Link],
userID:[Link]
})

if(!resume){
return [Link](404).json({message:"resume not found or not authorized"})
}
[Link](resume,[Link])

const saveResume = await [Link]()


[Link](saveResume)
} catch (error) {
[Link](500).json({
message:"failed to update resume",error:[Link]
})
}

export const deleteResume = async (req,res) => {


try{
const resume = await [Link]({
_id:[Link],
userID:[Link]._id
})
if(!resume){
return [Link](404).json({message:"resume not found or not authorized"})
}
const uplaodsFolder = [Link]([Link](),'uploads')

if([Link]){
const oldthumbnail=[Link](uplaodsFolder,[Link]([Link]))
if([Link](oldthumbnail)){
[Link](oldthumbnail)
}
}
if([Link]){
const oldProfile = [Link](
uplaodsFolder,
[Link]([Link])
)
if([Link](oldProfile)){
[Link](oldProfile)
}
}
const deleted = await [Link]({
id:[Link],
userID:[Link]._id
})
if(!deleted){
return [Link](404).json({message:"resume not found or not authorized"})
}
[Link]({message:"reusme deleted successfully"})
}
catch(error){
[Link](500).json({message:"faiiled to delete resume",error:[Link]})
}
}

ResumeRouters
import express from 'express'

import {protect} from '../middleware/[Link]'


import { createResume , deleteResume, getResumebyID, getUserResume, updateResume} from
'../controller/[Link]'
import { formToJSON } from 'axios'
import { uploadResumeImage } from '../controller/[Link]'

const resumeRouter = [Link]()


[Link]('/',protect,createResume)
[Link]('/',protect,getUserResume)
[Link]('/:id',protect,getResumebyID)

[Link]('/:id',protect,updateResume)
[Link]('/:id/uplaod-image',protect,uploadResumeImage)
[Link]('/:id',protect,deleteResume)

export default resumeRouter


[Link]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Upload</title>
</head>
<body>
<h1>Upload Image</h1>
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="image" required />
<button type="submit">Upload</button>
</form>

<% if (imageUrl) { %>


<h2>Uploaded Image:</h2>
<img src="<%= imageUrl %>" width="300" />
<% } %>
</body>
</html>

[Link]
import fs from 'fs'
import path from "path"

import Resume from '../models/[Link]'


import upload from '../middleware/[Link]'

export const uploadResumeImage = async (req,res)=>{


try {
[Link]([{name:"thumbnail"},{name:"profileImage "}])
if(!Resume){
return [Link](400).json({message:"file upload failed",error:[Link]})
}
const resumeId = [Link];
const resume = await [Link]({_id:resumeId, userId:[Link]._id})
if(!resume){
return [Link](404).json({message:"resume not found"})
}
const uplaodsFolder = [Link]([Link](),"uploads")
const baseURL = `${[Link]}://${[Link]("host")}`;
const newThumbnail = [Link]?.[0]
const newProfileImage = [Link]?.profileImage?.[0]

if(newThumbnail){
if([Link]){
const oldthumbnail =
[Link](uplaodsFolder,[Link]([Link]))
if([Link](oldthumbnail))
[Link](oldthumbnail)
}
[Link]=`${baseURL}/uploads/${[Link]}`;

if(newProfileImage){
if([Link]?.profilePreviewURL){
const oldProfile =
[Link](uplaodsFolder,[Link]([Link]))
if([Link](oldProfile))
[Link](oldProfile)
}

[Link]=`${baseURL}/uploads/${[Link]}`;
}
await [Link]();
[Link](200).json({
message:"image uploaded successfully",
thumbnaiLink:[Link],
profilePreviewURL:[Link]
})

}
catch (error) {
[Link]("error uploading image",error)
[Link](500).json({
message:"failed to upload images",
error:[Link]
})
}
}
[Link]
import multer from 'multer'
const storage = [Link]({
destination:(req,file,cb)=>{
cb(null,"uplaods/")
},
filename:(req,file,cb)=>{
cb(null,`${[Link]()}-${[Link]}`)
},
});
const fileFilter = (req,file,cb)=>{
const allowedTypes=["iamge/jpeg","image/png","image/jpg"]
if([Link]([Link])){
cb(null,true)
}
else{
cb(new Error("only .jpeg, .jpg , .png are allowed formats"),false)
}
}
const upload = multer({storage,fileFilter})
export default upload

[Link]
import mongoose from "mongoose";
export const connectDB = async () => {
await
[Link]('mongodb+srv://nakul172005:123@[Link]/RESUME
')
.then(()=>{[Link]("DB CONNECTED")})
}

[Link]
import express from "express"
import cors from "cors"
import 'dotenv/config'
import { connectDB } from "./config/[Link]";
import userRouter from "./routes/[Link]";
import path from 'path'
import { fileURLToPath } from "url";
import { url } from "inspector";
import resumeRouter from "./routes/[Link]";
import multer from 'multer';
import cloudinary from 'cloudinary'
import fs from 'fs';

const __filename = fileURLToPath([Link])


const __dirname = [Link](__filename)
const app = express();
const PORT = 3000;

[Link](cors())\
connectDB()

// middlwware
[Link]([Link]())
[Link]('/api/auth',userRouter)
[Link]('/api/resume',resumeRouter)
[Link](
'/uploads',
[Link]([Link](__dirname,'uploads'),{
setHeaders:(res,_path)=>{
[Link]('access-control-allow-origin','[Link]
}
}
)
)

[Link]('/',(req,res)=>{
[Link]('API WORKING')
})

[Link]("view engine", "ejs");


[Link]("views", [Link](__dirname, "views"));
[Link]([Link]([Link](__dirname, "public")));
const upload = multer({ dest: "uploads/" });
[Link]({
cloud_name: [Link].CLOUD_NAME,
api_key: [Link].CLOUD_API_KEY,
api_secret: [Link].CLOUD_API_SECRET,
});
[Link]("/ejs", (req, res) => {
[Link]("upload", { imageUrl: null });
});
[Link]("/upload", [Link]("image"), async (req, res) => {
try {
const result = await [Link]([Link]);
[Link]([Link]);
[Link]("upload", { imageUrl: result.secure_url });
} catch (err) {
[Link](err);
[Link]("Upload failed!");
}
});
[Link](PORT,()=>{
[Link](`server started on [Link]
})
CHAPTER- 4
TESTING & IMPLEMENTATION

The Smart Portfolio Builder project was thoroughly tested to ensure smooth functionality and
user experience. Functional, unit, and interface testing verified that all features—such as form
validation, data storage, and PDF generation—worked as intended. Browser compatibility
and responsive design were also tested to ensure proper display across devices. During
implementation, HTML and CSS were used for layout and styling, while JavaScript handled
form logic and data persistence using the Local Storage API. The jsPDF library was
integrated to generate downloadable portfolio PDFs. The system was developed and tested in
Visual Studio Code and Google Chrome, requiring no additional setup for deployment.
Overall, the application performed efficiently, meeting all design and functional objectives.

Screenshots-
• Home Page-

• Themes-
• Login/Sign Up Page-
• Portfolio Creation Page-
• Backend-
CHAPTER- 5
CONCLUSION & REFRENCES

The Smart Portfolio Builder project successfully provides an easy-to-use platform for
creating personalized digital portfolios. It combines simplicity with modern design, allowing
users to input their details, preview, and download their portfolios seamlessly. Through
effective use of HTML, CSS, JavaScript, and jsPDF, the system achieves both functionality
and aesthetic appeal. Overall, the project fulfills its goal of helping users professionally
showcase their profiles in a visually appealing and accessible format.

References-
1. Mozilla Developer Network (MDN Web Docs) – Documentation for HTML, CSS,
and JavaScript.
2. W3Schools – Tutorials and examples for front-end web development.
3. jsPDF Official Documentation – Guide for client-side PDF generation.
4. [Link] and MongoDB Documentation – For understanding backend integration
concepts.
5. Visual Studio Code User Guide – Setup and usage instructions.
6. Google Chrome DevTools – For testing and debugging web applications.
CHAPTER- 6
ANNEXURES

Smart Portfolio Builder Project


• Annexure A: Folder Structure (SmartPortfolioBuilder)
• Annexure B: Code Samples (HTML, CSS, JavaScript)
• Annexure C: Screenshots (Landing Page & Form Page)
• Annexure D: Environment Configuration (Tool & Version List)
• Annexure E: Workflow Documentation (Portfolio Creation Process)

Figures:
• Figure 1: Landing Page Screenshot (Placeholder)
• Figure 2: Portfolio Creation Form Screenshot (Placeholder)
• Figure 3: Generated Portfolio Preview Screenshot (Placeholder)

You might also like