Portfolio
A site born from the need to have a portfolio and the drive to learn an in-demand technology like Next.js.
Built with a custom WordPress plugin replacing ACF, server-side API fetching via the WordPress REST API, and a pragmatic deploy solution designed around real hosting constraints.

Personal Project
2 Months
UX/UI Designer - Developer

Context and Motivation
This portfolio was more than a showcase. It was a learning project with a specific technical goal: to work with the same tools and patterns used in scalable frontend projects, without relying on paid plugins or shortcuts.
I had prior experience with WordPress and React, so Next.js was the natural next step. It is widely adopted, ready for production, and something I had not yet used professionally.
Decoupling the frontend from the CMS was new to me, and I wanted to understand headless architecture by actually building it.
The outcome is a flexible and scalable setup: a Next.js frontend consuming a WordPress REST API, with custom-built data structures instead of third-party dependencies. This architecture allows me to expand the portfolio over time, adding new projects or sections without reworking the core structure.
Technical Architecture
The project consists of two independent layers.
The frontend runs on Next.js with the App Router and is deployed on Vercel. It handles routing, rendering, and all interactive behavior on the frontend, fetching data exclusively from the WordPress REST API.
The backend, WordPress, is hosted on Aruba and serves purely as a headless CMS. It does not render any frontend output and provides structured data through its API.
This separation allows the frontend to be rebuilt, migrated, or replaced without touching the content layer, and vice versa. It is a pattern that scales naturally to larger projects where frontend and backend teams operate independently.

Custom Plugin
ACF Without the Price Tag
One of the decisions I am most satisfied with is replacing ACF with a custom-built WordPress plugin. I have worked extensively with this tool in previous projects. It is a reliable solution for adding custom fields and structured data to WordPress, but some of the functionalities I needed are only available in the paid version.
In the spirit of treating this project as a learning and exploratory exercise, I decided to build a custom plugin that replicates the functionality I wanted.
I created 'Portfolio CPT Plugin', a plugin that registers custom post types for each content section of the portfolio and exposes structured page options through a custom REST API endpoint.
This approach is fully transparent, free of external dependencies, and gave me the opportunity to understand how WordPress structures its functions, how custom post types and page options are generated, and to deepen my knowledge of PHP. It also allowed me to fully customize blocks according to my needs, giving complete control over content and layout.



API Consumption in Next.js
With WordPress exposing clean, structured data, the Next.js side is responsible for fetching, organizing, and rendering it.
I used native fetch with Next.js App Router conventions, using server components for data fetching, keeping API calls on the server side and passing only what's needed to the client. This approach keeps the frontend performant and the data flow predictable.
The patterns here, fetching from an external API, structuring the response, separating server and client responsibilities, are the same ones used in larger frontend applications consuming any REST API, not just WordPress. This is a deliberate demonstration that the skills behind this portfolio translate directly to production-scale projects.
Design
The design process started in Figma, where I built the design system first: defined the color palette, typography, spacing, and component styles before touching any code. Having a solid DS upfront meant that translating everything into Tailwind and custom CSS was straightforward and consistent.
Orange was a deliberate choice. It is my favorite color, but beyond that it communicates energy and confidence, which is exactly what I wanted my personal brand to project. The interface is modern and uncluttered, with enough contrast to keep it accessible without sacrificing personality.
For the animations, I decided against using a library like Framer Motion to keep the bundle light and stay in control of the behavior. Instead I built a custom useReveal hook using the Intersection Observer API, paired with a RevealSection component that wraps any element and triggers a CSS transition when it enters the viewport. The component supports multiple animation directions, configurable delay, and threshold, making it reusable across the entire site.
The result is a scroll experience that feels fluid and intentional, not decorative. The animations accompany the reader through the page rather than interrupting them.


Deploy & Domain Conflict
Deploying a decoupled stack revealed an unexpected challenge. I had already purchased hosting with the domain melisadebartolo.com before defining the architecture.
When I later decided to go headless and deploy the frontend separately on Vercel, a conflict emerged: the frontend ideally needed the same domain for consistency with my email and to make it more intuitive for visitors, but it was tied to the hosting required for WordPress. Using the root domain for the frontend would have meant moving WordPress to another hosting plan, which I didn’t want to do because I didn’t want to waste the hosting I already had.
To resolve this, I deployed the Next.js frontend on Vercel under the subdomain portfolio.melisadebartolo.com and used a redirect plugin on WordPress to route visitors from melisadebartolo.com there. This allowed visitors to access the main domain while keeping the URL consistent and memorable, while WordPress stayed at the root on the existing hosting, serving only API responses behind the scenes.
Ideally, the frontend would live at the root domain with no redirects, but adding another server just to free the domain wasn’t a cost I could justify. It’s not perfect, but it works, and that’s the point. In real projects, ideal conditions are rare. Budget, existing infrastructure, and time constraints shape decisions. The goal isn’t perfection; it’s finding the best solution with what you actually have and shipping it. This tradeoff is known and something I plan to revisit when the domain comes up for renewal.
Working with AI
I used AI (Claude) throughout this project as a technical collaborator to work through implementation details, debug, and move faster on the parts where I needed to refresh my React knowledge. The decisions about architecture, plugin structure, and data design were entirely mine, and AI helped me execute them. That’s how I see AI working in any professional context: human judgment guides the project, while the tools accelerate the work.
