Anton Bohachuk
← ALL WORK

Vibe

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

Type
Client work
Year
2023
Duration
~1 month
Team
Solo
Vibe
Context

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.

Problem

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.

Stack

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.

SHAPE
Public site
Next.js · NextUI · Tailwind
Admin panel
prices · barbers · gallery
NestJS API
TypeORM
Data base
PostgreSQL
Server filesystem
gallery images
Altegio
booking widget
TypeScriptNext.jsReactNextUITailwind CSSNestJSTypeORMPostgreSQLAltegio
Decisions

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.

Outcome
no sitetwo locations
both live before the second shop opened
Instagram DMsbooking widget
appointments without a conversation
methe owners
who update prices, barbers and photos

First paid project. Handed over and still running on the content the owners maintain themselves.

Trade-offs

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.

Contact

Let's talk

Open to full stack roles, remote or on-site in Varna. The fastest way to reach me is email or Telegram.

ANTON BOHACHUK · VARNA, BULGARIA (EET)© 2026