Over the past few days, I did something that, looking from the outside, seems small: I created a web application for a World Cup pool within the Guaxinil community.
The idea was simple.
The gang enters with their Discord account, makes their game predictions, tries to predict the group standings, follows the ranking, and competes for some symbolic prizes: a Steam game key for the first-place winner and a month of Discord Nitro for the second-place winner.
Nothing too corporate. Nothing with a massive scope. Nothing that needs to turn into a startup.
Just a fun idea for the community.
But, as almost always happens when we build something real, the project became more interesting just when it stopped being "just a screen with predictions."
The Product Begins When the Game Needs to Work
At first, the idea seemed to be just:
“Let's make a pool for the community.”
But soon, decisions started to appear that changed the experience quite a bit:
How to prevent anyone outside from participating?
How to correctly identify each player?
How to validate that the user is a member of the Discord server?
How to organize the World Cup games in a coherent way?
How to separate score predictions, group standings, and knockout rounds?
How to make the ranking fun, but not a visual mess?
How to turn a game into an experience that feels like it belongs to the community?
That's the type of thing I like in small projects: they expose real decisions without the weight of a massive operation.
The application didn't need to be complex. But it needed to be careful.
The Stack Was Simple, But Intentional
I used a stack that's already part of my workflow:
Next.js
TypeScript
Tailwind CSS
Shadcn/UI
Prisma
PostgreSQL
Auth.js/NextAuth
Discord OAuth
Motion for some interactions
The most interesting technical part was integrating the login with Discord and restricting access only to members of the Guaxinil server.
Authentication alone would only solve half the problem. Anyone could log in with Discord. What I needed was a rule closer to the real context:
“You only participate if you're part of the crew.”
So the flow became something like this:
The user logs in with Discord.
The application saves the user's main data.
The system checks if they're a member of the Guaxinil server.
If they are, it unlocks access.
If not, it shows a restricted access screen with an invitation to join the community.
It may seem like a detail, but it changes the product perception a lot.
The application stops being just a public page and becomes an extension of the community itself.
The Ranking Became Part of the Experience
One of the most fun parts was turning the ranking into something with a "community event" feel.
I didn't want a cold table with names and points.
The idea was to make the ranking have a bit of visual identity, almost like collectible cards or figurines. So the top players got special cards with their Discord avatar, position, score, correct answers, and that controlled visual excess that fits a gaming community.
This type of detail isn't technically required, but it makes a difference emotionally.
Because, in the end, the ranking isn't just a list.
It's where the noise happens.
It's where someone prints that they're in first place.
It's where someone complains that they lost points for betting with club spirit.
It's where the community starts interacting with the product.
And that's much more interesting than just "displaying data."
The Challenge of World Cup Data
Another interesting technical point was dealing with World Cup games.
My first question was: is there an official, simple, and free API to consume the games?
The practical answer was: not quite ideal.
So I opted for a more controlled approach: structuring the data in JSON files, importing it into the database, and leaving the application ready to work with games, groups, teams, knockout rounds, and results.
This gave me more control and avoided turning a community project into a fragile dependency on an external API.
For the context of the pool, it made much more sense to have:
base data imported;
results updated in a controlled way;
ranking calculated internally;
clear rules for scoring.
It's a simple decision, but an important one: not every automation is worth the complexity it adds.
A Game Also Requires a Product
What caught my attention most in this project was realizing that even a small application goes through the same product layers as larger projects.
There's a user.
There's a context.
There's a business rule.
There's authentication.
There's permission.
There's data.
There's visual experience.
There's communication.
There's community.
And perhaps that's the main insight: product doesn't start when the project is big. Product starts when someone needs to use it for real.
Even if it's just a pool.
Even if it's just a game.
Even if the prize is a game key and a month of Nitro.
The difference is in treating the experience with care.
The Guaxinil as a Laboratory of Ideas
The most fun thing is that Guaxinil has become a space where these ideas can happen in a relaxed way.
It's a community for sharing ideas, playing, studying, sharing things, testing projects, laughing at questionable choices, and, every now and then, turning an inside joke into a functional application.
This pool was born exactly from that type of environment.
It didn't come from a formal demand. It came from a desire to create something for the gang to use.
And that reminded me of something important: not every project needs to be born with a big pretension. Sometimes, building something small for real people is enough to learn a lot.
If you want to join Guaxinil, share ideas with us, play, study, follow the projects, and participate in these crazy organized events, the invitation is here:
The crew is open.
Share on:
No spam. Only content worth opening.