Portfolio Site
This site, rebuilt from flat HTML to Next.js with an AI chatbot, MDX content pipeline, and streaming Anthropic integration. 95+ Lighthouse score.
Why Rebuild
My previous portfolio was a flat HTML/CSS/JS single-page site. Functional, but it contradicted my resume: I claimed Next.js and TypeScript expertise while the site itself used neither. The rebuild closes that credibility gap and turns the portfolio into a proof of skill.
Before writing a line of code, I studied Brittany Chiang's v4 portfolio and Terry Godier's work to understand what makes a developer portfolio feel credible. I borrowed structural confidence from Brittany's layout and editorial depth from Terry's case study approach, then adapted both to fit my own content and aesthetic.
Technical Decisions
Next.js 15 App Router with TypeScript strict mode. Server Components where appropriate, client components only where interactivity requires it. Static generation via generateStaticParams for all content pages.
Tailwind CSS v4 with CSS custom property design tokens for the dual dark/light palette. No @apply, utility classes throughout, with a custom .prose-custom class for MDX content styling.
MDX content pipeline using next-mdx-remote and gray-matter. Blog posts and case studies live as .mdx files in the repo, are statically generated at build time, and support draft mode for local previewing.
Framer Motion for meaningful animations: staggered hero reveal, scroll-triggered section entrances, spring-physics chat panel, hover interactions. All wrapped in useReducedMotion checks.
The Ask John Chatbot
The headline feature. A streaming AI chatbot powered by claude-sonnet-4-20250514 that answers questions about my experience in my voice.
Architecture:
- Edge runtime route handler for low cold-start latency
- Streaming via
ReadableStream, no Vercel AI SDK dependency - Seven protection layers: Upstash Redis rate limiting, input/output token caps, conversation length limits, honeypot, timing-based bot detection, input sanitization, and origin checking
- Conversations logged to Neon Postgres for review
The most interesting technical challenge was the cost protection infrastructure. Setting up Upstash Redis for sliding-window rate limiting (10 requests per IP per hour) and Neon Postgres for conversation logging required integrating two external services at the edge runtime layer while keeping cold-start latency low. The rate limiter needed to work on Vercel's Edge Functions with the package, and the Postgres logging needed to be non-blocking so it wouldn't slow down the streaming response. Getting all seven protection layers to work together without adding noticeable latency was the real puzzle.