Skip to content

v2.0.0: Next.js redesign

Choose a tag to compare

@kamycoding kamycoding released this 09 Nov 12:27
6f584b5

Overview

Version 2 is a full rebuild of kamycoding.com, the personal portfolio of Kamyar Zamanfar, in Next.js. The whole site is designed as a code editor: each section is a file, with a terminal, a command palette, line-drawing project covers and a cat. It ships in English and German, in a dark and a light theme, as static pages on Netlify. v1 (Angular) stays available at v1.0.0.

Highlights

  • Editor design: file tabs as navigation, rulers, breadcrumbs and a status bar; sections as index.tsx, work.tsx, about.md, stack.json and contact.ts
  • Hero: typed headline, editor panel with TypeScript-style hover cards, and a terminal with 13 commands, history and Tab completion
  • Work: ls -la project list with a pointer preview and a README drawer per project; line-drawing covers as SVG components
  • About: Markdown-style text, an ASCII portrait with a lens that reveals the photo, experience as a git log and reviews as pull request approvals with links to the reviewers' LinkedIn profiles
  • Stack: foldable JSON tree, a commit heatmap of the v1 history and services as functions
  • Contact: a sendMessage({ ... }) form with TypeScript-style errors, validated by the same schema in the browser and in the Netlify function
  • Global interactions: a pnpm build intro on load, command palette (Ctrl K / ⌘ K), keyboard shortcuts and a custom cursor with action labels
  • English and German: English at /, German at /de, browser language detection; a language switch keeps the reading position
  • Legal pages: legal notice and privacy policy in both languages; the privacy policy describes the language cookie and the theme setting

Contact form and backend

  • No separate backend: the contact form is a Netlify Function with Brevo for email delivery (ADR 0002)
  • One zod schema for the form and the function; unknown fields and control characters in the name are rejected
  • Only JSON from the own origin is accepted (415, 403), bodies above 10 KB are rejected before parsing (413)
  • The Brevo request times out after at most 8 seconds
  • Rate limiting (5 requests per 3 minutes per IP) and a honeypot that browser autofill leaves alone
  • One log line per request (accepted with Brevo's message ID, honeypot, validation rule, rejection reason, provider status), never names, emails or message text

Security

  • Enforced Content Security Policy with upgrade-insecure-requests and security headers: HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy and Cross-Origin-Opener-Policy (ADR 0005)
  • No X-Powered-By header; the language cookie is a Secure session cookie
  • security.txt and a security policy with GitHub private vulnerability reporting
  • CodeQL code scanning, Dependabot, secret scanning with push protection
  • No tracking, analytics or third-party scripts

Quality

  • CI on every push and pull request: frozen install, lint, type check, tests and build, with actions pinned to full commit SHAs
  • Unit tests with Vitest for the contact function (including every request check and the privacy-safe logging), the shared schema, the scroll spy, the commit heatmap and the language switch position
  • Accessibility: keyboard access everywhere, visible focus, reduced motion respected, labels that include the visible text, small text at WCAG AA contrast
  • Metadata per language with canonical and language alternates, Open Graph images, a sitemap; legal pages are noindex

Tech stack

Next.js 16, React 19, TypeScript, Tailwind CSS v4, next-intl, next-themes, Geist, zod, Vitest, Netlify Functions, Brevo, pnpm

Getting started

Requirements: Node.js 24 (.nvmrc) and pnpm (pinned in package.json, enabled through corepack).

git clone https://github.com/kamycoding/portfolio.git
cd portfolio
git checkout v2.0.0
corepack enable pnpm
pnpm install
pnpm dev

The app runs at http://localhost:3000. The contact function needs the variables in .env.example and is tested end to end on Netlify Deploy Previews.

Full changelog

https://github.com/kamycoding/portfolio/blob/v2.0.0/CHANGELOG.md