Pular para o conteúdo principal

Indo para produção

A demo omite várias coisas que uma integração de produção precisa. Esta página lista a distância entre ela e algo por onde você passaria dinheiro.

O que a demo pula

FaltandoPor que importa
Contas e sessões de jogadorA demo pega um playerRef de uma caixa de texto
Carteira, saldo, débito de entradaNinguém paga para entrar, e ninguém recebe
Sessões reais de provedordemoSessionUrl() retorna uma URL falsa
PersistênciaLiquidações vivem num Map e morrem no restart
Uma fila atrás do webhookEla liquida inline; uma real enfileira e retorna
AutenticaçãoToda página é pública
KYC, jogo responsável, jurisdiçãoQuais jogadores podem jogar

Tudo isso fica do seu lado da fronteira, e o SlotBattle não vai desenvolver isso. Veja O que o SlotBattle não faz.

Faça isto antes de aceitar dinheiro

Debite a entrada antes de abrir a batalha, e torne isso reversível. Batalhas podem terminar failed ou cancelled. Decida a sua política de estorno antes de precisar de uma, e faça um webhook battle.failed disparar isso automaticamente, e não por ticket de suporte.

Liquide dentro de uma transação, com chave de idempotência. A entrega é ao menos uma vez, então uma duplicata vai chegar em algum momento e não pode pagar duas vezes.

Nunca liquide pelo socket. Ele é melhor esforço e não tem replay.

Cheque ok por assento. Uma batalha completed pode conter um assento que falhou.

Emita sessões de provedor por jogador, no servidor. game_url é uma sessão de dinheiro ao vivo. Ela não aparece em nenhuma resposta, log, evento ou webhook do SlotBattle; mantenha a mesma linha nos seus logs.

Verifique que a fronteira se mantém

npm run build
grep -r "sbk_" dist/ && echo "LEAK" || echo "clean"

Rode isso na CI. Uma chave num bundle de cliente não é algo que revisão de código pegue de forma confiável; é algo que você pega dando grep no artefato construído.

Confirme também que lib/slotbattle.ts nunca é alcançável de um componente de cliente. O guard em runtime pega isso em desenvolvimento; o grep pega o que o guard não pega.

Realidade operacional

503 unavailable é normal sob carga. A instância limita batalhas em voo. Retente com backoff exponencial e jitter; esse é o único erro rotineiramente retentável.

Tokens de viewer expiram em 15 minutos. Emita de novo na reconexão, e quando uma página ficar aberta mais tempo que isso.

Rotações de chave de assinatura deveriam ser invisíveis. O operador nomeia uma chave nova e deixa a antiga verificando até se aposentar, então tokens já nos browsers continuam funcionando. Espectadores tomando 401 no socket de repente significa que a rotação foi feita sem janela. Reemitir é a sua mitigação, e a rotação deve ser reportada.

Deploys podem falhar batalhas em voo. Uma batalha no meio da gravação depende de gravadores que já estão rodando. Trate battle.failed como desfecho rotineiro, não como exceção.

Assista a uma gravação real de ponta a ponta. Um gravador sem aceleração de GPU cai para cerca de 2 fps: a gravação termina com sucesso e fica impossível de assistir. Nenhuma checagem automática pega isso, então uma pessoa precisa olhar.

Checklist final

  • Nenhum sbk_ em bundle de cliente, checado na CI
  • A verificação de assinatura de webhook recusa um corpo adulterado, testado e não presumido
  • A liquidação é idempotente sob entrega duplicada
  • Assentos com ok: false são excluídos dos pagamentos
  • battle.failed e battle.cancelled disparam estorno automaticamente
  • 503 é retentado com backoff; 400/409 não
  • Um espectador que chega tarde renderiza um lobby correto
  • Tokens de viewer são reemitidos na reconexão
  • game_url não aparece em nenhum log que você controla
  • Uma gravação completa foi assistida por uma pessoa

Por onde seguir