Project · Case study

How I built this site

From a Wix template to a hand-built Next.js app, and the design decisions along the way.

August 2025 – presentSource on GitHubBack to resume

Why rebuild it

The first version of stevesuhr.com was a Wix site. It did the job, but I didn't own any of it. For a software engineer's resume, the site itself should be evidence. So I rebuilt it by hand, with two goals: a showcase I could point people to, and a sandbox for learning Next.js and Postgres on a real deployed app instead of a tutorial.

Stack

Next.js 15 + React 19
App Router, server components, and server actions. The resume page is prerendered as static HTML; the side projects render on the server per request.
TypeScript
Used for everything new. The original resume components are still plain JavaScript and get converted when I touch them.
Tailwind CSS + CSS custom properties
Tailwind for layout utilities, plus a small set of hand-written design tokens for color and type so light and dark mode come from one place.
NextAuth (Google sign-in)
Real authentication for the side projects without storing passwords myself.
Prisma + Postgres on Neon
A typed ORM over serverless Postgres. Sessions and user data live in the same database as the projects that use them.
Vercel
Hosting and deploys from GitHub. Every pull request gets a preview build.

How it evolved

v1: the flashy version

Aug 2025

A full-screen hero with a parallax background, GSAP scroll animations, and gradient cards for each job. It was a good way to learn the framework, and it looked like a lot of other developer portfolios.

Sandbox features

Aug 2025

Added Google sign-in, then Postgres through Prisma, then a small signed-in to-do app to exercise the whole path: auth, database, server actions, and per-user data access checks.

Midway through I migrated from the Pages Router to the App Router and upgraded to Next.js 15. Running both routers side by side for a while made the tradeoffs concrete, especially around where session data gets loaded.

v2: the document redesign

Sep 2026

I replaced the hero, parallax, and animations with a layout that reads like a well-edited document: a masthead, a sticky table of contents, and numbered sections. The content is the same; it's just much easier to skim.

Design decisions

  • Built for skimming. Most people give a resume under a minute. Numbered sections and a table of contents let a reader jump straight to experience, and the numbers come from CSS counters, so adding or hiding a section never means renumbering by hand.
  • Three typefaces, three jobs. Serif for names and headings, sans for body copy, and monospace for metadata like dates, locations, and skills. You can tell what a line is before you read it.
  • One set of color tokens. Warm neutrals with a single amber accent, defined once as CSS variables and redefined for dark mode. Secondary text meets WCAG AAA contrast (7:1) in both themes, after feedback that the gray was hard to read on a phone in bright light.
  • Static where it can be. The layout used to read the session on every request, which forced the resume to render dynamically. Moving the auth check into a client component let the resume be prerendered as static HTML, while the signed-in projects still render on the server.
  • Motion only where it helps. The scroll animations are gone. What's left is small hover feedback on links, and it turns off for anyone with reduced motion enabled.
  • Mobile first-class. Below 900px the two-column layout collapses, and the table of contents becomes a compact grid at the top instead of a sidebar.

Tools

I used AI coding assistants (OpenAI Codex and Anthropic's Claude) for parts of the work, like the App Router migration and the v2 restyle. I made the design and architecture calls and reviewed every change before it merged, the same way I would with a teammate's pull request.