Sylvino Prevot
Case Study // 002

3R
Barber

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

A 3R Barber saiu da agenda de papel e do WhatsApp bagunçado. Desenvolvi o app de agendamento do zero: cliente reserva sem criar conta, barbeiro vê a fila em tempo real, admin acompanha receita por loja. As duas unidades rodam nele, em produção desde julho de 2026.

2

Lojas Atendidas

Em Produção Monorepo

Galeria do Produto

Home com as duas unidades da barbearia e a fila ao vivo.

Saiba mais sobre a arquitetura técnica

Quer entender como isso foi construído por baixo do capô? Abra o mergulho técnico abaixo.

expand_more

Visão Técnica

3R Barber é uma barbearia com duas lojas. Construí o app de agendamento como monorepo pnpm — API, frontend e pacote compartilhado — rodando no free tier da Cloudflare, sem custo mensal pro cliente. O cliente reserva sem conta: escolhe loja, serviço, barbeiro (ou 'qualquer barbeiro') e acompanha por um link único. Barbeiro e admin têm painel próprio pra fila, agenda e relatório.

Tecnologias Principais

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

O Desafio

Sistema de agendamento pronto não falta no mercado — o problema é que todos cobram mensalidade. Eu precisava entregar reserva pública, fila em tempo real e dashboard com métricas sem custo de infraestrutura, mantendo o horário certo entre fusos e isolando de verdade o acesso de cada papel:

  • / Converter corretamente horários de funcionamento em BRT para timestamps UTC na geração de slots de agendamento.
  • / Suportar agendamentos com 'qualquer barbeiro', onde o primeiro a atender ganha o cliente, sem gerar conflitos de concorrência.
  • / Isolar dados por papel (client/barber/admin) garantindo que um barbeiro só acesse a própria fila e agenda.
  • / Evitar agendamentos duplicados por reenvio de formulário (duplo clique, retry de rede) sem exigir conta do cliente.
check_circle

A Solução

A API roda em Hono no Cloudflare Worker, Drizzle sobre D1, toda mutação validada por Zod. Autenticação e RBAC ficam com o Better Auth. Toda rota de barbeiro busca primeiro o próprio registro pelo usuário logado — um barbeiro não acessa a agenda de outro. A conversão BRT→UTC fica num único helper no backend. Reserva duplicada (duplo clique, retry de rede) é barrada na aplicação e reforçada por um índice único no banco.

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

Infraestrutura

architecture

Deploy & CI/CD

API na Cloudflare Workers, frontend na Cloudflare Pages, os dois no free tier. Testes E2E com Playwright cobrem o fluxo de reserva inteiro, contra um banco D1 isolado recriado do zero a cada execução.

Projeto Anterior Portfólio Pessoal
Próximo Projeto BlipLeads