Voltar ao índice
03Trabalho

Roleta Online

Sorteio por cotas, com vaga limitada

Meu papel
Desenvolvedor full stack
Cliente
Catsuc Labs
Setor
Produto de consumo · web
Status
Em produção

Código proprietário. Sistema privado de cliente — o repositório não é público.

Números

20/40/100

capacidades de roleta

O sorteio dispara no instante em que a última vaga é preenchida.

1

ficha por posição

Garantido por restrição única no banco, não por checagem no código.

0

vaga vendida duas vezes

Alocação transacional — o banco recusa a segunda venda.

A

Contexto

Bolão de cotas é um formato antigo e conhecido: um grupo divide um prêmio em partes iguais, cada um compra a sua e um sorteio decide. Levar isso para a web parece trivial até você perceber que a parte interessante não é a roleta girando — é o que acontece quando duas pessoas clicam em comprar a última ficha no mesmo milissegundo.

B

O problema

Vaga é finita e tem dinheiro envolvido. Isso transforma três coisas em requisito duro: nenhuma posição pode ser vendida duas vezes, nenhum pagamento repetido pode gerar ficha extra, e o sorteio precisa ser explicável depois — porque quem perdeu vai querer entender como perdeu.

C

A abordagem

Coloquei as garantias no banco, não no código de aplicação. Cada posição da roleta é uma linha com restrição única, e a compra acontece dentro de uma transação que ou reserva a posição ou falha — o banco recusa a corrida, em vez de a aplicação torcer para não acontecer. A confirmação de pagamento é idempotente por chave, então reenvio de webhook não vira ficha nova. E o sorteio grava a semente e o resultado, para poder ser reconstruído depois.

D

Módulos

01Capacidade e estado

Roletas

Cada roleta tem capacidade, preço da ficha e estado — aberta, cheia, sorteada. O estado é do servidor: o cliente exibe, não decide.

02Compra e alocação

Fichas

Comprar uma ficha é reservar uma posição numerada dentro de uma transação. Se a roleta encheu no meio do caminho, a compra falha limpa e o valor não é capturado.

03Disparo e registro

Sorteio

Roda no instante em que a última vaga é preenchida, uma única vez por roleta, com semente e resultado persistidos.

04Auditoria

Histórico

Quem comprou qual posição, quando, e qual foi o resultado. Sem isso não existe confiança num produto onde alguém perde dinheiro.

E

As partes difíceis

A última ficha e duas pessoas clicando

É o problema central, e não se resolve com “verifica se ainda tem vaga antes de gravar” — entre a verificação e a gravação cabe outra requisição. A posição é uma linha com restrição única e a reserva acontece na transação: a segunda venda simplesmente não é aceita pelo banco. Deixar a garantia no nível mais baixo possível é o que torna o resto do código simples.

Webhook chega duas vezes

Provedor de pagamento reentrega notificação — é comportamento normal, não exceção. Sem idempotência por chave, a segunda entrega gera uma ficha que ninguém pagou. Tratar reentrega como o caso esperado, e não como erro, é a diferença entre um produto que fecha a conta e um que não fecha.

O resultado tem que ser defensável

Num produto de sorteio, a suspeita é o padrão. O sorteio roda uma vez só por roleta, guarda a semente e o resultado, e não pode ser rodado de novo — nem por mim. Poder reconstruir o sorteio depois vale mais que qualquer animação de roleta girando.

F

O que é meu

  • Modelagem das roletas, posições e fichas, com as garantias de unicidade no banco
  • Fluxo de compra transacional e confirmação de pagamento idempotente
  • Disparo do sorteio no preenchimento da última vaga, com registro auditável
  • Interface de participação, acompanhamento do preenchimento e histórico
G

Resultado

Um formato de bolão que funcionava no papel passou a funcionar sozinho na web, com vaga limitada, dinheiro real e resultado reconstruível. Foi o projeto que mais me ensinou sobre concorrência — não a teoria, a versão em que errar custa o dinheiro de alguém.

O que eu levei

  1. 01Garantia de integridade pertence ao banco. Checagem na aplicação é uma sugestão, restrição é uma lei.
  2. 02Reentrega de webhook é o caso normal. Idempotência não é refinamento, é requisito.
  3. 03Em produto onde alguém perde, auditabilidade é feature de confiança — não de compliance.

Stack