Skip to main content

Project

Portfolio Site Modernization

Rebuilt my portfolio from a static AWS-hosted resume into a modern Next.js 15 site with Tailwind CSS v4, MDX content pipeline, Pagefind search, dark/light theme, PWA support, and Cloudflare Pages deployment.

Type
Web / Portfolio
Status
Active
Years
 -
Portfolio Site Modernization architecture diagram
  • Next.js
  • Tailwind CSS
  • MDX
  • TypeScript
  • Cloudflare Pages
  • Pagefind
  • Zod

Overview

The original Cloud Resume Challenge site was a static HTML resume on S3 and CloudFront. It demonstrated serverless architecture, but it was a single page — no room for project write-ups, build logs, or anything beyond a resume. This project replaced it with a production portfolio built for long-term use, then modernized it with search, validation, and developer experience features.

Architecture

The site runs on four layers:

Content pipeline — Blog posts and project pages are authored in MDX. At build time, Zod schemas validate every metadata export (titles, dates, tags, status fields), catching errors before they reach production. A remark/rehype plugin chain then transforms the content: GitHub Flavored Markdown, automatic layout wrapping, heading ID generation via rehypeSlug, Shiki syntax highlighting, and image unwrapping. A loader function discovers all MDX files with fast-glob, validates metadata, and sorts entries by date.

Application layer — Next.js 15 with the App Router handles routing, static generation, and React Server Components. Tailwind CSS v4 provides utility-first styling through CSS-native configuration. Framer Motion adds scroll-triggered animations, and the View Transitions API provides smooth page-to-page transitions natively in the browser. The entire site is TypeScript with Zod runtime validation.

Features layer — Pagefind provides static full-text search with a keyboard-accessible dialog (Ctrl/Cmd+K). Blog posts get auto-generated table of contents from headings, reading time estimates, and dynamic Open Graph images for social sharing. An RSS 2.0 feed serves blog content to feed readers. Cloudflare Web Analytics tracks usage without cookies.

Deployment — GitHub pushes trigger Cloudflare Pages builds. The site pre-renders 60+ static HTML pages, Pagefind indexes them for search, and everything deploys to Cloudflare's edge network.

What I Built

  • Homepage with hero banner, about section, latest blog posts, and featured project cards
  • Project pages with architecture diagrams, technical breakdowns, and linked build log series
  • Blog system with MDX, syntax highlighting, reading time, table of contents, and tag-based filtering
  • Static search — Pagefind indexes all pages at build time with data-pagefind-body scoping, modal search dialog, keyboard shortcut, and inline search on the 404 page for dead link recovery
  • Dark/light theme — Toggle with localStorage persistence and system preference detection, no flash of wrong theme
  • RSS feed — Full blog content (not just descriptions) served at /feed.xml via content:encoded for feed readers
  • Dynamic OG images — Auto-generated social preview images per blog post and project using next/og
  • Copy-to-clipboard — One-click code copying on every code block across the site
  • MDX callout components — Reusable info, warning, danger, and tip boxes for rich blog content
  • PWA support — Service worker for offline access, installable as a homescreen app
  • Experience section with structured job data, detail pages, and skill grids
  • About page with certifications, education, and professional values
  • Toolbox page showcasing tools and technologies
  • Full SEO — JSON-LD structured data, dynamic sitemap, Open Graph images, web app manifest
  • Security headers — Content Security Policy, X-Frame-Options, Referrer-Policy, Permissions-Policy
  • Accessibility — Skip-to-main link, focus-visible outlines, semantic HTML landmarks, external link handling
  • Schema validation — Zod validates all MDX metadata at build time, catching missing or malformed fields early
  • Image strategy — Blur placeholders on raster images and responsive sizes (static export serves images as-is, so sources are pre-sized rather than transcoded at request time)
  • Bundle analysis@next/bundle-analyzer for monitoring JS bundle size
  • Performance hints — DNS prefetch and preconnect for third-party scripts
  • Testing — Vitest unit and integration tests covering components, page composition, and the MDX loader with Zod validation, run in CI on every pull request

Key Decisions

DecisionChoiceWhy
FrameworkNext.js 15Static generation + React components + mature MDX support
StylingTailwind v4CSS-first config, no JS config file, @theme design tokens
ContentMDX in repoVersion-controlled, no external CMS, JSX when needed
ValidationZodRuntime type checking catches metadata errors at build time
SearchPagefindStatic index, no server needed, works offline, tiny bundle
TransitionsView Transitions APINative browser API, no JS framework weight, respects prefers-reduced-motion
HostingCloudflare PagesFree, fast builds, DNS already there, simpler than S3+CloudFront
AnalyticsCloudflare Web AnalyticsPrivacy-first, no cookies, free, minimal script
ThemingCSS variables + JSDynamic dark/light toggle, no flash, system preference aware
OfflineService worker PWACache-first for assets, network-first for navigation
SecurityCSP + security headersXSS protection, clickjacking prevention, strict referrer policy
AnimationsFramer MotionDeclarative API, useInView scroll triggers, React-native
TestingVitestFast unit + integration tests, jsdom, native ESM/TS support

Read More

More projects

Azure Web Store on Kubernetes

Microservices web store on AKS — Java Spring Boot services, Azure B2C identity, API Management gateway, and GitHub Actions CI/CD.

Read more

Text-to-Speech Serverless App

Serverless multilingual text-to-speech app on AWS — Cognito auth, Lambda processing pipeline, Polly synthesis, and Terraform IaC.

Read more