Building My Portfolio Site From Scratch
Recently I found myself thinking "I should update my CV" every few weeks. At some point I realized I was spending more time thinking about and maintaining a PDF than actually working on things worth putting in it.
I was applying to a few positions I was genuinely interested in, and I noticed that many of them had a field for a personal website. That planted the idea, and once I started thinking about it the reasons kept stacking up: a website is stable, I can keep it updated easily, it's accessible to anyone with a link, and it doesn't get lost in an email thread.
There's also a practical side that I didn't fully appreciate until the site was live. When my LinkedIn, my blog, or any application includes a link to the portfolio, whoever's looking at it — a recruiter, a potential collaborator — already has everything they need without contacting me. My stack, my experience, case studies of what I've worked on. A lot of the small back-and-forth I used to do manually (sending updated CVs, answering "what technologies do you work with?") is now just a page someone can read. It filters out irrelevant proposals and gives the right information to the right people without me doing anything.
Starting from a weekend
I built the first version in a single weekend working almost non-stop. The result is far from finished, I'm still working on it, but the base is solid enough that I can share it and keep iterating.
One constraint I set early was that the whole thing had to cost 0€/month. That meant doing some research on hosting, email services, and image delivery before writing any code. I ended up with Next.js on Vercel for the frontend (static site generation, free tier), and Resend for the contact form. The site is fully statically generated at build time — no runtime API calls, no database, no server to maintain.
// Content is loaded from YAML files at build time — no runtime fetching
export async function getProjectCaseStudy(
slug: string,
locale: string
): Promise<ProjectCaseStudy> {
const filePath = path.join(contentDir, locale, `${slug}.yaml`);
const raw = await fs.readFile(filePath, "utf-8");
const parsed = yaml.load(raw);
// Validate required sections before returning
return validateCaseStudy(parsed);
}The whole infrastructure runs at zero cost. Vercel handles the CDN and deploys, GitHub hosts the source, Resend sends contact form emails. Nothing to manage, nothing to pay for.
Claude Code and nWave did the typing
I delegated the code writing almost entirely to Claude Code paired with nWave — a framework that sits on top of Claude Code and breaks AI-assisted development into sequential phases called "waves" (discover, discuss, design, devops, distill, deliver), each handled by a specialized agent. The phases go from validating the problem all the way to implementation through Outside-In TDD. I can run the full pipeline or jump to whichever wave fits the situation — for this project I mostly used the delivery and design waves.
The part I find most valuable is that the machine never runs unsupervised. Every wave produces artifacts I review before the next one starts, and a system called DES enforces discipline on the agents — tracking file modifications, blocking skipped TDD phases, gating handoffs between waves through reviewer agents.
I was making the architectural and design decisions while nWave's agents wrote the code. I picked the tech stack, decided how to organize features, chose the visual direction, defined what the case study pages should look like. A portfolio site is a good fit for this kind of workflow — the requirements are clear, the scope is bounded, and most decisions are easy to validate visually.
A timeline with room to dig deeper
The site is built around a timeline. Work experience, education, personal projects — everything sits on a vertical timeline that gives visitors a quick overview of what I've done and when.
If someone wants to go deeper — say, a recruiter curious about a specific project — each entry can link to a full case study. These have sections like "The Problem", "The Decisions", "What Didn't Work", and "The Bigger Picture". I wanted them to show how I think about problems, not just which tools I used.
# Case study content lives in YAML files per locale
title: "SagitterHub"
type: "work"
hook: "Enterprise platform for credit recovery automation"
metrics:
- label: "Code Coverage"
value: ">90% (TDD)"
sections:
theProblem: |
Four separate legacy tools, each handling a piece of
the credit recovery workflow...
theDecisions: |
Hexagonal Architecture with DDD tactical patterns...Everything is bilingual — English and Italian — with `next-intl` handling locale-based routing and content switching. The content itself lives in YAML files that get parsed at build time, so adding a new case study means creating a new file, not touching any React components.
It's all on GitHub
The whole project is open source. Anyone who wants something similar can fork it, swap in their own content files, and deploy. The structure is generic enough that it works for any developer, and the content layer makes it easy to customize without touching component code.
Work in progress
I'm happy with the base I put together in a short time. It's already live and I'm using it in applications. There are still small issues to fix, sections to refine, and a few more case studies to write. The nice thing about having a living site instead of a static PDF is that it grows with me — every new project just becomes another entry on the timeline.
The CV was always something I maintained reluctantly, as a chore. The site is something I actually want to work on.