Sinpete
Credenciamento de evento decidido contra uma métrica só: o tempo que uma pessoa leva para passar pela portaria. Arquitetura, RBAC de 5 níveis e QR saíram dessa escolha.
Tecnologias
Fila na portaria
800msEm produção, uso real
500+Papéis de acesso
5O problema
O pedido que chegou era "um sistema de credenciamento" — escopo aberto o bastante para justificar meses de tela. A primeira decisão foi recusar o escopo por funcionalidade e escolher **uma** métrica de sucesso: o tempo que um participante leva para atravessar a portaria, com teto de 2 segundos. A justificativa é operacional, não técnica: em evento de grande porte, tudo que dói (fila, tumulto, erro de digitação, participante irritado) é sintoma desse número. Uma segunda restrição veio junto: a portaria funciona com o aparelho que o credenciador tem no bolso, não com um leitor dedicado.
A decisão
Com a métrica fixada, cada escolha técnica passou a ter um critério de aceite óbvio. Next.js (App Router) + React 19 com Server Components para tirar peso do bundle que roda no celular da portaria. Prisma 7 sobre Neon Postgres para não ter servidor ocioso entre eventos. Autenticação em NextAuth v5 com middleware próprio conferindo RBAC no nível de rota **e** de componente — 5 papéis, porque o cliente tem 5 papéis reais, não porque a granularidade fosse elegante. Na portaria, leitura por câmera validando um JWT curto embutido em QR dinâmico: a validação acontece no token, não numa ida ao banco, que é o que mantém o número onde ele precisa ficar. Relatórios em PDF e Excel saem de forma assíncrona, sob demanda, justamente para não competir com o check-in pela CPU.
O resultado
A plataforma opera em produção com mais de 500 usuários reais, e o check-in ficou em torno de 800ms por participante — dentro do teto que definiu o projeto. O que eu faria diferente: o número de 800ms veio de medição de campo informal, não de instrumentação no código. Num projeto cujo argumento é a métrica, ela deveria estar sendo registrada a cada leitura, não observada no relógio.
