How to build a gambling app without spending a dime on servers

How to build a gambling app without spending a dime on servers

Disclaimer: this blog is not just for sports fans

The vast majority of the Super Bowl’s approximately 100 million annual viewers aren’t actually fans of the teams taking the field. They’re just people who are just looking for an excuse to get together with friends, eat healthy amounts of seriously unhealthy food, and watch commercials.

But if congeniality and carbohydrates aren’t enough to hold your interest, a little action can make the “Big Game” a bit more interesting. 

Historically, most of the wagering on Super Bowl Sunday happens not at the big Vegas sportsbooks like Caesar’s or MGM, but instead in people’s homes, with friendly, informal wagers. The reigning champion of gambling games is a simple-to-learn, no-sports-knowledge-needed game commonly called “Super Bowl Squares.” 

With many in-person party plans getting sidelined these past few years, we had an idea:

Create a “Roacher Bowl Squares” app to help distributed gamblers get their Big Game betting fix.

Don’t worry. This blog isn’t for sports fans or even gambling fans. In fact, before I started building this app, I couldn’t name more than two NFL teams (…there’s the Indianapolis Colts because I lived in Indianapolis and supporting them was a requirement. I might have shed a tear when Peyton Manning left. The other is the Patriots, because again, I lived in Indianapolis and we hate them).

This blog is about my experience building an interactive serverless application with Prisma, Remix, Netlify, Pusher Channels, and CockroachDB Serverless. Why did I choose Remix over Next.js? Was that even a good decision? Do I regret it? Read on dear reader….let’s find out. 

It’s hip to be square: How this sample gambling app works

First, a quick README on how the game typically works:

  • A blank 10x10 grid is created. Typically on a sheet of paper.
  • The X and Y axes are labeled with the team names of the Super Bowl competitors.
  • Players claim squares from the blank grid at a preset dollar amount per square.
  • Once every box of the pool has been sold, the numbers 0-9 are randomly assigned to each row and column.
  • At the end of every quarter, the person whose square corresponds with the intersection of the second digit of each team’s score wins a prize (for example, a 14–7 score at the end of the first quarter pays out the owner of the square at column 4, row 7).

It’s conceptually pretty simple, but presents a handful of interesting challenges to solve when attempting to replicate this traditional, in-person version as a serverless application. 

Below I’ll walk through some of the highlights, but if you’d prefer to just view the code, you can do that as well.

Remix vs Next.js: My Gambling App Tech Stack

Before getting into the complicated gymnastics of gambling application architecture let’s take a look at the players on the field (not sorry!). One of the first decisions I made was to use Remix instead of Next.js. I usually use Next.js for web applications but I decided to give Remix a try for two reasons:

• It’s the new hotness and I love shiny things
• The people behind Remix are amazing (Kent C. Dodds, so glad he’s okay)

I immediately regretted my decision. And I spent a few hours cursing into the ether because I put myself in position to learn a brand new framework from scratch in order to build a sample app in a matter of days.

And then I started to love Remix. I could probably dedicate an entire blog post just fan boying Remix. In short I’ll just say I think it’s great that you can write an application using Remix and turn off JavaScript and it’ll still work. Just go try it already.

The rest of my tech stack looks like this:

CockroachDB Serverless

This application is far from stateless. We need a database to hold information about users, and the different games that are happening concurrently. CockroachDB Serverless is a great choice because of the nature of this application. A lot of the action takes place during The Big Game. Outside of that, the applications could be dormant only waking when participants are claiming their squares. This app takes advantage of CockroachDB Serverless’s elastic scale to provide compute when needed and be cost-effective when the demand recedes. 

Prisma 

Now that we have our database, we need a way to talk to it. Prisma is a typesafe ORM and my preferred way to work with CockroachDB. Prisma recently released preview support for CockroachDB. My dog and I actually appeared on the Prisma livestream to talk about a different sample app I built with the Prisma support for CockroachDB. I’ll link you straight to the good part (me): 

Netlify

Remix can be deployed to many different platforms and lets you select which to use when starting a new project. I chose Netlify because I’m most familiar with it. During the build process, Remix will package up the static assets and create a Netlify function to handle the server-side rendering of your application. Don’t want to use Netlify? You’re just a small change away from using Vercel, Fly.io, and many others. I like Netlify. Sue me. 

Pusher Channels

Just like with the Ugly Sweater app, we are using Pusher Channels to keep the game boards in sync while changes are being made. Before the game starts, this helps make sure no one tries to claim a square that was recently claimed by another participant. During the game, we get live updates of winning squares as the score changes.

Gambling application database schema

For the users:

  • id - UUID PRIMARY KEY DEFAULT gen_random_uuid()
  • username - STRING UNIQUE NOT NULL
  • password_hash STRING
  • created_at - TIMESTAMPTZ DEFAULT now()
  • updated_at - TIMESTAMPTZ DEFAULT now()

For the games:

  • id - UUID PRIMARY KEY DEFAULT gen_random_uuid()
  • slug - STRING (something human readable and unique)
  • host_id - UUID references to user table
  • state - STRING [INIT (default), Q1, Q2, Q3, Q4, FINAL]
  • claim_cost - DECIMAL (cost per square)
  • board - JSONB representation of the board
    Ex. {“teams”: [“Team 1”, “Team 2”], “rows” : [0, 1, 2, …, 9], “cols”: [0, 1, 2, …, 9]}
  • scores - JSONB

Ex. [[0,0], [0,0], [0,0], [0,0]]

  • winners - JSONB winners for all 4 quarters
    Ex. [{id: “”, name: “Jane Doe”, “userid”: “jd1”}, {id: “”, name: “Jane Doe”, “userid”: “jd1”}, {id: “”, name: “Jane Doe”, “userid”: “jd1”}, {id: “”, name: “Jane Doe”, “userid”: “jd1”}]
  • created_at - TIMESTAMPTZ

For the claims:

  • id - UUID PRIMARY KEY DEFAULT gen_random_uuid()
  • game_id - UUID
  • participant_id - UUID references to auth user table
  • row - INT
  • column - INT
  • created_at - TIMESTAMPTZ

The sample app is up, running, and waiting for you to host your own Roacher Bowl Squares game when the Big Game rolls around. 

Try it out, share screenshots of your game, and let us know what you think by tagging #RoacherBowlSquares or @CockroachDB on Twitter. 

We have lots more sample apps in our Resources library as well. I hope you’ll check them out.

Keep Reading

3 Common Foreign Key Mistakes (And How to Avoid Them)

Foreign keys are an important element of any relational database. But when you’re setting up your database schema, it’s …

Read More
How to build a multi-region Python app with CockroachDB, Django and K8s

A request came across my desk the other day asking whether I had any experience with Django and could I get it to work …

Read More
Build a Complete Jamstack App with CockroachDB and Netlify Functions

To help people get outdoors and improve their physical well-being, we’ll create an outdoor activity tracker. Although we …

Read More
x
Developer Resources