Pular para o conteúdo
PLSO.
Trabalho
Caso 01Pré-lançamento

EA Profissional

Site institucional, agendamento online e loja em um só produto. A regra que impede dois clientes de reservarem o mesmo horário não vive no código — vive no banco.

Cliente
EA Profissional
Segmento
Estética e beleza profissional
Local
Itabuna, Bahia
Escopo
Construção e operação contínua
Estado
Construído · aguardando publicação
modelos de dados
34
fases entregues
5 / 7
tabelas com RLS
100%
sobreposições no teste de concorrência
0
01 — O problema

Uma clínica de estética vive da agenda.

Um horário vendido duas vezes não é um erro de sistema: é um cliente que chega e não é atendido, uma profissional que precisa escolher quem dispensar, e uma reputação que leva meses para recuperar em uma cidade onde todo mundo se conhece.

E o negócio não cabia em um produto só. Precisava apresentar procedimentos com credibilidade, receber agendamento sem depender de troca de mensagens, e vender produto. Normalmente isso vira três ferramentas que não conversam entre si, três mensalidades e três lugares para o dado ficar desatualizado.

02 — A decisão que define o projeto

Verificar antes de gravar não é uma trava.

O caminho óbvio é consultar a disponibilidade no código antes de salvar. Funciona no teste, com uma pessoa por vez, e falha em produção no primeiro sábado cheio.

O que quebra

Duas requisições simultâneas leem a agenda no mesmo instante. As duas veem o horário livre. As duas gravam.

Por que o índice não resolve

Um índice único em (profissional, início) impede dois agendamentos com o mesmo horário de início. Não impede sobreposição parcial: 10:00–13:00 contra 11:00–12:00 passa.

Onde a regra passou a viver

Numa constraint de exclusão do Postgres. O Prisma não sabe expressá-la, então ela entra por migração SQL escrita à mão.

migração SQL · appointments
ALTER TABLE appointments
  ADD CONSTRAINT appointments_no_overlap
  EXCLUDE USING gist (
    "professionalId" WITH =,
    tstzrange("startsAt", "endsAt", '[)') WITH &&
  )
  WHERE (status IN ('PENDING', 'CONFIRMED'));

Intervalo semiaberto

O '[)' faz um atendimento que termina às 10:00 não conflitar com outro que começa às 10:00. Mesma semântica do motor de disponibilidade, para os dois nunca discordarem.

Constraint parcial

O WHERE deixa só agendamentos vivos ocupando a agenda. Cancelado e não comparecido liberam o horário sozinhos, sem rotina de limpeza.

Reserva temporária

A mesma proteção cobre a reserva que segura o horário enquanto o cliente preenche os dados — com índice de expiração, consultado a cada cálculo de disponibilidade.

A validação em código continua lá, como primeira linha de defesa e para dar uma mensagem decente ao usuário. Mas ela deixou de ser a última. O banco recusa a gravação mesmo que tudo acima dele falhe.

03 — Segurança

O banco fechado por padrão.

RLS em todas as tabelas

Row Level Security ativo nas 34 tabelas, fechando acesso direto ao banco. Um script audita e lista qualquer tabela que tenha escapado.

Configuração validada no boot

As variáveis de ambiente passam por validação de esquema na subida. Configuração inválida derruba o build — não a produção.

Trava provada, não presumida

Um script dispara reservas concorrentes contra o banco real e verifica que só uma sobrevive. A garantia é testada, não assumida.

04 — Entrega

Ordenado por conversão, não por módulo.

As fases não seguem a ordem em que o software fica pronto. Seguem a ordem em que passam a dar retorno.

  1. 00

    Fundação

    Design system, modelo de dados, componentes base, deploy.

    Entregue
  2. 01

    Institucional

    Procedimentos, resultados e SEO local.

    Entregue
  3. 02

    Agendamento

    Fluxo completo de reserva online.

    Entregue
  4. 03

    Loja

    Catálogo em vitrine, com venda pelo WhatsApp.

    Entregue
  5. 04

    Checkout

    Carrinho, pagamento e frete.

    Roadmap
  6. 05

    Painel

    Agenda, horários, procedimentos, produtos, estoque e avaliações.

    Entregue
  7. 06

    Área profissional

    B2B, curso e quiz capilar.

    Roadmap

A fase 3 ficou pronta em modo vitrine, com venda pelo WhatsApp, antes de o checkout existir. Ter o que vender antes de ter carrinho encurta o caminho até a primeira receita.

05 — Stack
Aplicação
  • Next.js 15
  • React 19
  • TypeScript estrito
  • Tailwind CSS
Dados
  • Postgres
  • Prisma
  • Row Level Security
  • Migrações SQL à mão
Garantias
  • Vitest
  • Playwright
  • Validação de esquema com Zod
Operação
  • Vercel
  • Deploy contínuo
  • Monitoramento
06 — Depois da entrega

O projeto não termina na entrega.

As fases 4 e 6 seguem no roadmap e a publicação está a caminho. O contrato é de operação contínua, não de entrega única: quando o site subir, ele já nasce monitorado, atualizado e medido — e continua recebendo melhoria sem novo orçamento a cada ajuste.