A personal portfolio site for Gerald Evan Johnson, built with MongoDB, Express, React (Vite), and Node.js.
- Resume content (experience, projects, skills, education) lives in
client/src/data/resumeData.js— edit it directly to update the site. - The contact form is fully functional: it POSTs to the Express API, saves the message to MongoDB, and emails Gerald via Nodemailer.
- Node.js 18+
- MongoDB running locally (
mongod), or a MongoDB Atlas connection string
cd server
npm install
cp .env.example .envEdit server/.env:
MONGODB_URI— defaults tomongodb://127.0.0.1:27017/portfoliofor a local MongoDB instance.SMTP_HOST/SMTP_PORT/SMTP_USER/SMTP_PASS— SMTP credentials used to email you contact-form submissions. For Gmail: enable 2-Step Verification, then create an "App Password" at myaccount.google.com/apppasswords and use that asSMTP_PASS.CONTACT_RECEIVER_EMAIL— where contact-form emails are delivered.
Run the API:
npm run devStarts on http://localhost:5000. If MongoDB isn't reachable yet, the server still starts (it logs a warning) but /api/contact won't be able to save messages until Mongo is up.
cd client
npm install
npm run devOpens on http://localhost:5173 and proxies /api/* requests to the Express server on port 5000.
Drop your headshot at:
client/public/images/profile.jpg
Until then, the hero section shows a circular initials avatar automatically — nothing breaks.
cd client && npm run build
cd ../server && npm startThe Express server serves the built React app from client/dist and the API from the same process/port.
- Reference contacts listed on the original resume were intentionally left off the public site to avoid publishing third parties' personal emails.
- Contact-form submissions are stored in the
messagescollection in MongoDB even if email delivery isn't configured, so nothing is lost.