Core Technologies
Project Stats
Lojas Atendidas
2
Papéis de Acesso
3
01. Technical Overview
3R Barber é um app de agendamento para barbearias construído como monorepo pnpm (apps/api, apps/web, packages/shared), rodando inteiramente no free tier da Cloudflare. O cliente reserva horário sem criar conta — escolhendo loja, serviço, barbeiro (ou 'qualquer barbeiro') e horário — e acompanha o agendamento por um link com token único. Barbeiros e administradores têm dashboards próprios para gerenciar fila, agenda, relatórios e configurações da loja.
The Challenge
O desafio central era entregar uma experiência de produto completa (reserva pública, fila em tempo real, dashboards com métricas) sem depender de nenhum serviço pago, mantendo consistência de horários entre fusos e isolando corretamente o acesso de cada papel de usuário:
- / 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.
02. The Solution
A API em Hono roda como Cloudflare Worker com Drizzle ORM sobre D1, validando toda mutação com schemas Zod (zValidator). A autenticação e o RBAC usam Better Auth com sessão por cookie, e cada rota de barbeiro busca o registro pelo userId autenticado antes de tocar em qualquer dado da loja. A conversão de horário fica centralizada em helpers de BRT no backend, e a proteção contra reserva duplicada combina checagem por telefone+loja+horário com um índice único no banco como reforço contra a corrida.
// 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
Deploy & CI/CD
API na Cloudflare Workers e frontend na Cloudflare Pages, ambos no free tier. Fluxo de reserva coberto por testes E2E com Playwright rodando contra um banco D1 isolado, recriado do zero a cada execução.