Sylvino Prevot
Case Study // 002

3R
Barber

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

3R Barber dejó atrás las agendas de papel y el desorden de WhatsApp. Desarrollé la aplicación de reservas desde cero: los clientes reservan sin crear una cuenta, los barberos ven la fila en tiempo real y el administrador monitorea los ingresos por sucursal. Ambas sucursales operan con ella, en producción desde julio de 2026.

2

Sucursales Atendidas

En Producción Monorepo

Galería del Producto

Inicio con las dos sucursales de la barbería y la fila en vivo.

Conozca más sobre la arquitectura técnica

¿Quiere entender cómo se construyó esto por debajo? Abra la inmersión técnica a continuación.

expand_more

Visión Técnica

3R Barber es una barbería con dos sucursales. Construí la aplicación de reservas como un monorepo pnpm — API, frontend y paquete compartido — funcionando en el free tier de Cloudflare, sin costo mensual de infraestructura para el cliente. El cliente reserva sin cuenta: elige sucursal, servicio, barbero (o 'cualquier barbero') y sigue su turno mediante un enlace único. El barbero y el administrador cuentan con su propio panel para fila, agenda y reportes.

Tecnologías Principales

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

El Desafío

No faltan sistemas de reservas prediseñados en el mercado; el problema es que todos cobran suscripciones mensuales. Necesitaba ofrecer reservas públicas, fila en tiempo real y un panel con métricas sin costo de infraestructura, manteniendo la precisión de horarios entre zonas horarias y aislando estrictamente el acceso según el rol:

  • / Convertir correctamente los horarios de atención en BRT a marcas de tiempo UTC al generar los turnos disponibles.
  • / Soportar reservas con 'cualquier barbero', donde el primero en atender toma el cliente, sin generar conflictos de concurrencia.
  • / Aislar datos por rol (cliente/barbero/administrador), garantizando que un barbero solo acceda a su propia fila y agenda.
  • / Evitar reservas duplicadas por reenvío de formularios (doble clic, reintentos de red) sin exigir una cuenta al cliente.
check_circle

La Solución

La API corre sobre Hono en Cloudflare Workers, con Drizzle sobre D1 y cada mutación validada por Zod. La autenticación y el RBAC están a cargo de Better Auth. Cada ruta de barbero consulta primero su propio registro mediante el usuario autenticado, impidiendo que un barbero acceda a la agenda de otro. La conversión BRT→UTC se centraliza en un único helper en el backend. Las reservas duplicadas (doble clic, reintentos de red) se bloquean en la aplicación y se refuerzan mediante un índice único en la base de datos.

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 };
}

Infraestructura

architecture

Deploy & CI/CD

API en Cloudflare Workers, frontend en Cloudflare Pages, ambos en el free tier. Pruebas E2E con Playwright cubren todo el flujo de reservas contra una base de datos D1 aislada que se recrea desde cero en cada ejecución.

Proyecto Anterior Portafolio Personal
Próximo Proyecto BlipLeads