Vibe
Barbershop site for a two-location shop, with an admin panel the owners run themselves.

A barbershop where my girlfriend was working had no website at all and was opening a second location. They needed something to point people at — services, prices, the barbers, photos of the work — and they needed it to cover both locations from day one.
This was the first thing I built that someone paid me for. It was also the first time the person receiving the work wasn't a teacher or a reviewer, but an owner who would have to live with whatever I handed over.
The owners didn't want a site they'd have to call someone about. Prices change, barbers come and go, new photos get taken — all of that had to be editable by people who don't write code and won't open a repository. So the deliverable wasn't a site, it was a site plus the tooling to keep it current, and the admin had to be plain enough that nobody needed training to use it.
Next.js for the public site and the admin panel, styled with NextUI and Tailwind. A NestJS API behind it, PostgreSQL through TypeORM for services, barbers, locations and gallery entries. Bookings open the shop's Altegio widget rather than a calendar of my own.
Ship the admin as part of the deliverable
The obvious version of this project is a static site with the prices hardcoded, handed over and then edited by me forever. Building the admin instead meant more work up front and none afterwards — services, barbers, locations and the gallery are all owner-editable, and I haven't had to touch the content since handover.
Two locations from the start
The second shop was opening as the site was being built, so locations are a first-class entity rather than a duplicated page. Barbers, prices and photos all belong to a location, and adding a third would be a row in a table rather than a rebuild.
Hand off booking rather than build it
Appointments go through Altegio, which the shop already used for its calendar. Building a booking system would have meant a second source of truth the staff would have had to keep in sync with the one they trusted — so the site opens the widget and stays out of the way.
First paid project. Handed over and still running on the content the owners maintain themselves.
Switching location is client state, not a URL. That means neither location has its own address — you can't link someone straight to the second shop, and search engines only ever see one version of the page. For a business whose customers find it by searching for a neighbourhood, that's the wrong call, and it's the first thing I'd change.
Gallery images upload to the API server's own filesystem and are served from there. It works as long as there's exactly one instance that never gets replaced — which is also to say it doesn't survive a redeploy onto fresh storage, a second instance, or a migration. Object storage is the answer and I didn't know to reach for it yet.
Let's talk
Open to full stack roles, remote or on-site in Varna. The fastest way to reach me is email or Telegram.
