Kickbet
Kickbet is a web app where you can guess the results of football matches and compare your guesses with those made by your friends. I built Kickbet specifically for the 2022 FIFA World Cup.
The rules are simple. You score:
- 3 points if you correctly guessed the result;
- 2 points if you guessed the goal difference;
- 1 point if you guessed the winner;
- 0 points otherwise.
When the tournament is finished, the person with the most points wins.
The architecture
Kickbet app
exposes a REST API and serves the UI;Redis
is used as user session storage;SendGrid
is used for sending emails via SMTP.
The deployment
I use an ansible playbook to set up the VM with:
- Docker + docker-compose;
- NGINX;
- certbot;
NGINX is configured to handle HTTPS and to rewrite the domain in the cookies to/from localhost to the production domain.
Whenever I need to deploy another version of the application, I use another playbook which deploys the docker-compose.yml
with the application (a specific docker image tag) and its dependencies.
I also set up two cron jobs:
- one which creates a backup of the database and sends it to S3 once a day;
- another one for renewing the SSL certificates;
Everything runs on a single $6 / month DigitalOcean droplet.
The tech stack for the app
Kotlin, Spring Boot, React. The React app is bundled and served as static content by the Kotlin app.
The fun stuff
- hexagonal architecture on the server side;
- business logic for automatic assignment of teams to a particular knockout stage match. Also, the logic that moves the teams up the knockout stage ladder;
- a database-based task queue based on a
SELECT ... FOR UPDATE SKIP LOCKED
query; - a tree of the knockout stage made only with a couple of
<div>
and a splash of CSS;
Lessons learned
Redis not really needed, but doesnt’t hurt at all to use it
For such a simple app with such a small number of users, I believe I could simply use the database to store the user sessions. Anyway, I think I spent less time configuring redis than I would’ve spent setting up the DB schema for storing the sessions.
Remember to set up the firewall
I initially forgot to set up the firewall on the VM. It didn’t even take 24 hours to kill my redis instance. I believe this stackoverflow post describes what happened to my server.