Sylvino Prevot
Case Study // 002

3R
Barber

Hono (Cloudflare Workers)Cloudflare D1 + Drizzle ORMBetter Auth (RBAC)React + Vite + React Router 7

3R Barber transitioned away from paper agendas and chaotic WhatsApp messages. I developed the scheduling app from scratch: clients book without creating an account, barbers view the queue in real time, and the admin monitors revenue per shop. Both locations run on it, in production since July 2026.

2

Shops Served

In Production Monorepo

Product Gallery

Home page featuring the barbershop's two locations and the live queue.

Learn more about the technical architecture

Want to understand how this was built under the hood? Open the technical dive below.

expand_more

Technical Overview

3R Barber is a barbershop with two locations. I built the booking application as a pnpm monorepo — API, frontend, and shared package — running on Cloudflare's free tier with zero monthly infrastructure cost for the client. Clients book without an account: they select location, service, barber (or 'any barber'), and track their status via a unique link. Barbers and admins have dedicated dashboards for queue management, schedule, and reports.

Core Technologies

Hono (Cloudflare Workers) bolt
Cloudflare D1 + Drizzle ORM database
Better Auth (RBAC) lock
React + Vite + React Router 7 web
Tailwind CSS v4 + shadcn/ui format_paint
Playwright (E2E) task_alt
warning

The Challenge

There is no shortage of off-the-shelf booking systems on the market — the problem is they all charge monthly subscriptions. I needed to deliver public booking, real-time queue management, and metrics dashboards with zero infrastructure cost, while ensuring accurate timezone handling across regions and strictly isolating access by role:

  • / Accurately converting BRT operating hours to UTC timestamps when generating booking slots.
  • / Supporting 'any barber' appointments, where the first available barber claims the client, without concurrency conflicts.
  • / Isolating data by role (client/barber/admin), ensuring barbers can only access their own queue and calendar.
  • / Preventing duplicate bookings from form resubmissions (double-clicks, network retries) without requiring client accounts.
check_circle

The Solution

The API runs on Hono in Cloudflare Workers, with Drizzle on D1 and all mutations validated via Zod. Authentication and RBAC are handled by Better Auth. Every barber route first retrieves the barber record based on the authenticated user — preventing one barber from accessing another's schedule. BRT→UTC conversion is centralized in a backend helper. Duplicate bookings (double-clicks, network retries) are blocked at the application level and reinforced by a unique index in the database.

apps/api/src/utils.ts
// Slot generation: BRT hora + 3 = UTC hora
const BRT_TO_UTC_H = 3;

export function getDayBounds(dateBRT: string) {
  const [y, m, d] = dateBRT.split("-").map(Number);
  const startTs = Date.UTC(y, m - 1, d, BRT_TO_UTC_H, 0) / 1000;
  const endTs = startTs + 24 * 60 * 60 - 1;
  return { startTs, endTs };
}

Infrastructure

architecture

Deploy & CI/CD

API on Cloudflare Workers, frontend on Cloudflare Pages, both on the free tier. E2E tests with Playwright cover the full booking flow against an isolated D1 database recreated from scratch on each run.

Previous Project Personal Portfolio
Next Project BlipLeads