This project emerged out of passion and necessity. A friend had recently
created a fantasy league but It was using google forms and google
sheets. Although functional the user experience wasn't great.
My primary objectives were
Create a functional and simple user experience
Feature parity with original excel version
A more interesting and informative team creation process
Desired Community building features
List of people streaming the event
League creation
League Moderation
Support for prize pools and entry fees
Creating a team
The first problem I wanted to tackle was improving the UX of the team
creation process. Removing any uncertainties about what impact your
choices have on points, and bonus points throughout the tournament.
One key issue I had when deciding on players was knowing if they
were actually good. In the original there was a separate spreadsheet
showcasing all stats for all players. I personally found this slow
and hard to use.
Instead, I went for a show on hover approach. If a user wanted to
know the player stats they can simple hover over them.
Another quality-of-life feature added was sorting the players. A simple
yet great way for users to find a player that fits in their budget.
Without this it can be easy to miss a cheap player as your scroll
through the teams.
Points
Seeing how your players are performing is a key part of the user
experience. As a user, you want feedback on your decisions.
When you open your team page, you are greeted with all of the players
you selected. They also include your applied bonuses. I also opted for
a simple point element for simplicity. If a user wants further
details, all they need to do is scroll to see a more detailed points
table.
Rate Limiting with Redis
After seeing a video about Upstash from the youtuber Theo I realised it would be good idea to add some basic rate limiting.
After setting up the redis db on upstash I went ahead and added
middleware to my project.
This tracks the number of requests each ip makes and if it hits the
limit of requests it will forward the user /api/blocked. It required
some testing to ensure a genuine user navigating the site doesn't hit
the rate limit. I landed on 10 requests per second being the cap. Most
pages only have 1-2 requests to the API at a time so if someone were to
activate the rate limit there must have been a fair amount of spamming.
It was important to me that I did not have to be involved in running the
tournaments themeselves. I set out to make a simple dashboard for
verified users to access and manipulate league and player details.
The image below shows a page that admins can access to edit player
details. I use an Amazon S3 bucket to store player images and use a
service called "UploadThing" to manage upload and retrival.
It's important for an admin to be able to know the populaity of each
player duing the tournement. We use this information to adjust prices as
the event goes on in an attempt to create more variety in teams. I.E. If
player Y is listed at $20,000 but has not been picked we will reduce his
price by $1000
Building a profanity filter
Because users team names will be visible publicly on the home page of a
league its important to make sure they are moderated in some way. The
first solution I found was a profanity filter package on npm - bad-words.
If the string included a profanity, it would replace it with ***. This
was ok as I would be able to detect if the name had a profanity before
they submitted it and make them change it. The issue with this and every
other package I find was the if the profanity was merged with other
letters, it would not be detected. For example, profanityyyyyyyy would
be deemed acceptable.
After a long search I decided to make my own instead. I got a list of
all swear words/slurs from oxford dictionary and would run a regex
comparison. Now as long as any word included a listed word it was marked
as profanity.
note: This solution isn't perfect as there are words/names that
are considered appropriate that include profanities. For example,
"Dickens". But I decided that it would be better to have false positives
than negatives.