← Todos os artigos
6 min de leitura

O dia em que um QR Code substituiu 20 minutos de fila

Lançar o Parusya para usuários reais me ensinou mais sobre engenharia de software do que qualquer projeto acadêmico. O código foi a parte fácil.

Tem um momento no desenvolvimento de qualquer sistema que separa teoria de realidade.

Não é quando você faz o primeiro commit. Não é quando o deploy funciona. Não é nem quando os testes passam.

É quando uma pessoa real, que não sabe nada sobre o seu código, usa o sistema pela primeira vez — e você está do lado de fora, sem poder ajudar, só observando.

Esse momento chegou numa sexta-feira à noite, num estacionamento.

Os meses antes

O Parusya levou meses para sair do papel. Não meses de desenvolvimento contínuo — meses de decisões, erros, refatorações, e aquela sensação constante de que "ainda não está pronto".

O backend em Java com Spring Boot foi tomando forma: autenticação JWT com criptografia RSA assimétrica, três perfis de usuário em tabelas separadas, geração de QR Code via ZXing, constraints de unicidade no banco para impedir check-in duplicado. O frontend em React com leitor de câmera via html5-qrcode. Deploy no Railway, Vercel, Cloudflare.

Em algum momento, a lista de coisas para fazer parou de diminuir — e eu percebi que estava procrastinando o lançamento. O sistema funcionava. Eu é que não estava pronto para ele falhar na frente de todo mundo.

Mas tinha uma semana marcada. E ela chegou.

O momento

300 jovens chegando. Equipe de recepcionistas com celular na mão, logados como EventStaff. Eu do lado de fora fingindo estar tranquilo.

O primeiro participante chegou.

Abriu o celular. Mostrou o QR Code. A recepcionista apontou a câmera.

Bip.

Nome apareceu na tela. Check-in registrado. Timestamp gravado no banco com participant_id, event_id, staff_id e o horário exato de chegada.

Eu quase chorei no estacionamento. Não porque foi tecnicamente impressionante — mas porque eu vi o momento exato em que um problema deixou de existir.

Nenhuma fila. Nenhum nome digitado errado. Nenhuma planilha travando. Nenhum estresse.

Só um QR Code e meio segundo.

O código é a parte fácil

Mas sabe o que ninguém te conta sobre lançar um sistema para usuários reais?

O código é a parte fácil.

O que realmente testou o sistema não foi a complexidade técnica. Foi o encontro com o comportamento humano — e com todas as situações que eu não havia previsto sentado na frente do computador.

Convencer a equipe a mudar a rotina. A planilha existia há anos. As pessoas sabiam usar. Mudar rotina gera resistência, mesmo quando a nova opção é melhor. Foi necessário treinar, explicar, mostrar em tempo real que era mais simples — não apenas dizer que era.

O cadastro precisava ser simples de verdade. Eu sabia que o sistema era fácil de usar. Mas "fácil para quem construiu" e "fácil para uma pessoa de 60 anos que nunca criou conta em nada" são coisas completamente diferentes. A tela de cadastro foi redesenhada três vezes até chegar num fluxo que qualquer pessoa completava sem pedir ajuda.

3G fraco no estacionamento. Esse foi o teste de estresse que eu não havia simulado. A câmera abria, lia o QR Code, enviava o request — mas em conexões lentas o feedback demorava 2, 3 segundos. Para a recepcionista, parecia que havia travado. A solução foi melhorar o feedback visual: um spinner claro, mensagem de "processando", e estado desabilitado no botão enquanto aguardava resposta.

O participante sem celular. Acontece. A pessoa esqueceu o celular no carro, ou a bateria morreu. Para esses casos, mantivemos um fluxo alternativo: a recepcionista pode fazer check-in pelo nome diretamente no sistema. Não é o fluxo principal, mas precisa existir.

Produto não é só o que você constrói. É o que acontece quando pessoas reais usam o que você construiu.

A decisão técnica que salvou a noite

Antes do lançamento, eu tinha corrigido um bug que poderia ter comprometido tudo: check-in duplicado.

O cenário era simples: uma recepcionista escaneia o QR Code de alguém que já entrou. Talvez por acidente, talvez porque a pessoa voltou para buscar algo. Sem proteção, o sistema registraria duas presenças para a mesma pessoa no mesmo evento.

O relatório final diria 320 presentes. A realidade seria 300.

Apresentar dados errados para a coordenação — dados que influenciam decisões sobre o grupo — destruiria a confiança no sistema inteiro.

A solução foi dupla. Primeiro, uma verificação na camada de aplicação:

if (checkInRepository.existsByParticipantIdAndEventId(participantId, eventId)) {
    throw new BusinessException(ErrorCode.DUPLICATE_CHECKIN);
}

Mas só isso não era suficiente. Em condições de alta concorrência — 100 pessoas chegando ao mesmo tempo, múltiplos celulares escaneando simultaneamente — dois requests poderiam passar pela verificação de aplicação ao mesmo tempo, antes que qualquer um deles tivesse gravado no banco.

A segunda camada foi uma constraint diretamente no banco de dados:

@Table(
    name = "check_ins",
    uniqueConstraints = {
        @UniqueConstraint(
            columnNames = {"participant_id", "event_id"}
        )
    }
)

Mesmo que o frontend falhe. Mesmo que dois celulares escaneiem o mesmo QR Code no mesmo segundo. O banco rejeita. O dado está protegido.

Essa é a diferença entre um sistema que funciona no demo e um sistema que funciona na vida real:

Nunca confie só na camada de aplicação para garantir integridade de dados. O banco precisa ser a última linha de defesa.

O que o estacionamento me ensinou

Saí daquela noite com uma compreensão diferente do que significa construir software.

Quando você escreve código para um exercício de faculdade, o critério de sucesso é: compila, passa nos testes, entrega. O usuário é um professor que vai rodar casos de teste específicos.

Quando você constrói para pessoas reais, o critério de sucesso é outro. A pergunta não é "o sistema funciona?" — é "o sistema funciona quando Dona Maria de 60 anos, com um celular Android velho e 3G fraco, tenta se cadastrar pela primeira vez às 19h30 com 15 pessoas na fila atrás dela?"

Essa pergunta muda tudo. Muda o que você prioriza. Muda o que você testa. Muda o que você considera "pronto".

Nenhuma aula me ensinou isso. Uma noite num estacionamento ensinou.

O Parusya hoje processa mais de 1.000 check-ins por mês. A equipe usa sem precisar de treinamento. Os dados são confiáveis o suficiente para a coordenação tomar decisões baseada neles.

Mas o que fica de verdade não é o número. É a memória do primeiro bip — e da certeza de que um problema havia deixado de existir.

← Ver todos os artigos