Agendamento online com horário marcado para prestadores de serviço no Brasil.
Um único núcleo de produto atende múltiplas verticais por configuração — não por código. Cada estabelecimento tem uma Vitrine pública sob URL própria, onde o cliente escolhe serviço, profissional e horário sem precisar ligar ou mandar mensagem; o gestor administra agenda, equipe, serviços, produtos, planos de cliente e cobrança por um painel próprio. Sobre isso há uma camada de plataforma: assinatura por níveis, ciclo de vida de conta integrado ao gateway de pagamento e um console interno de operação e suporte.
- Next.js 15
- React 19
- TypeScript
- Tailwind v4
- PostgreSQL 16
- Prisma 6
- Auth.js v5
- pg-boss
- Zod 4
- Vitest
- Docker
- GitHub Actions
- Caddy
- VPS própria
Destaques técnicos
Integridade de agenda garantida no banco
O anti-double-booking é uma constraint EXCLUDE USING gist do PostgreSQL sobre o intervalo do atendimento. Duas requisições concorrentes para o mesmo horário não dependem de o código lembrar de checar: o banco recusa.
Disponibilidade calculada, não persistida
Os horários livres são computados sob demanda a partir das janelas do profissional, aplicando exceções, buffer, antecedência mínima e horizonte máximo. Sem tabela de slots para desincronizar; datas em UTC, exibição em America/Sao_Paulo.
Modelo revisado quando não aguentou
A unidade de reserva deixou de ser o agendamento e passou a ser a Comanda: um container que agrega N agendamentos, produtos e cobrança numa visita só. Cancelar um item no meio do bloco sobe os seguintes na mesma transação.
Notificações no padrão outbox
Todo e-mail nasce como linha em tabela, gravada após o commit da regra de negócio — falha de e-mail nunca derruba um agendamento. Um worker separado despacha em lote com retry e backoff, com idempotência por chave única no banco.
Ciclo de conta como máquina de estados
Seis estados, cada transição disparada por evento — webhook, job ou ação de operador —, nunca por cálculo de relógio na leitura. O efeito de acesso é resolvido por uma única função consumida por todas as rotas.
Cobrança sem superfície PCI
O cadastro não coleta nem tokeniza cartão: checkout hospedado do gateway para cartão, fatura hospedada para PIX. Nenhum dos dois muda o estado da conta — quem ativa é o webhook de pagamento, validado por token e idempotente.
- ~59 mil
- linhas de TypeScript/TSX
- 29
- modelos de dados
- 63
- páginas e route handlers
- 253
- testes automatizados
