See also: API documentation
With all the money to be made selling information, BDPA Media Conglomerate decided to create a microblogging and social networking service called Barker! Your team has been contracted to build the Barker platform, where users will interact with each other through immutable 280-character text messages known as "barks".
Summary of requirements (15 total)
The app supports two user types: guests and authenticated users. Users interact with each other through immutable 280-character messages known as Barks. Users can like, share, reply to, bookmark, and otherwise interact with each other's Barks.
The app has at least four views: Home, Pack, Bookmark, and Auth. The Home view is the primary view and is the gateway to the Barker platform. Pack view is a specialized version of the Home view. Bookmark view is like Pack view except with a unique sorting order. The Auth view is used for handling authentication as only authenticated users can access the Pack and Bookmark views and create new Barks.
Note that time-based data in the API is represented as the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. See the API documentation for details. Further note that you must use the API to complete this problem statement, including interacting with data from other chapters, though you may consider a hybrid approach where you have your own database storing non-API data.
We're looking for feedback! If you have any opinions or ideas, start a discussion.
Your app will support 2 types of users: guest and authed.
- Are unauthenticated users (i.e. don't have to login)
- Can access the Home view
- Can access the Auth view
- Are authenticated users (i.e. users that have already logged in)
- Can access every view
Home view: create and interact with Barks from followed users.
- "Barks" are 1 to 280 character messages that cannot be edited after creation.
- Barks appear in a scrollable list, colloquially referred to as a "wall" or "feed".
- Clicking a Bark will change the browser URL to point to the clicked Bark; each Bark will be reachable via its unique URL.
- Navigating to a Bark's URL in the browser will show the user that specific Bark. How to implement users seeing/scrolling to a specific Bark after entering its URL is up to your team.
- Each Bark shows the name of the user that created it and some way for others to follow them.
authed
users are shown Barks only from the users they follow. They also see their own Barks. On the other hand,guest
users are shown all Barks in the system.- An
authed
user can create new Barks and delete (called "rescind" in the UI) old Barks.- Barks can be created normally or as a reply under another Bark (called a "bark-back" in the UI).
- When a Bark is "deleted," it is not removed from the system. Instead,
deleted/rescinded Barks have their
deleted
flag set in the API; this will be reflected in the UX.
- An
authed
user can interact with a Bark by "liking" it, sharing it (called a "rebark" in the UI), replying to it with a bark-back, and bookmarking it.- Rebarking is the same as posting a new Bark, except the contents are copied from a pre-existing Bark.
- A bark-back is like posting a new Bark, except it's directly in response to another Bark. Bark-backs cannot be created in response to other bark-backs!
- Each Bark shows the total number of likes ❤️, rebarks 📢, and bark-backs 🐺 that are associated with it.
- Each Bark shows some sort of timestamp describing when it was created.
Each Bark will be displayed in the order described below.
Social media and e-commerce corporations are spending billions of dollars crunching exabytes of data developing complex algorithms that still fail to answer "which X is my user most likely to like," but we'll give it our best shot.
Ideally, we would show the user the Barks they are most likely to like. This way, they stay scrolling in the app, maybe even becoming addicted to our content. The challenge is accomplishing this with only a priori knowledge. That is: we don't actually know which Barks the user will like until we observe them pressing the like button, but we can develop an algorithm that makes a decent guess.
This algorithm must sort the list of Barks such that the "most likeable" Barks are displayed first. We define a Bark's relative "likeability" as some combination of the recentness of a Bark (users are more likely to be interested in the latest content) and the number of likes a Bark has received (things a lot of people like are more likely to be liked by the user too).
Barks will first be grouped by creation time in one hour intervals. For example, yesterday's barks between 12:00 AM and 1:00 AM should be in the same group, and yesterday's barks between 1:00 AM and 2:00 AM should be in another group, etc., and today's barks between 12:00 AM and 1:00 AM should be in another group, and so on.
Within each interval group, Barks should be sorted by number of likes first then creation time second, both in descending order. For example, given the following (unsorted) Barks from followed users A, B, and C:
{ "owner": "C", "content": "Bark Bark Bark", "createdAt": 3619, "likes": 0 },
{ "owner": "C", "content": "Bark Bark", "createdAt": 3615, "likes": 1 },
{ "owner": "B", "content": "Hello world", "createdAt": 3610, "likes": 3 },
{ "owner": "A", "content": "Third bark!", "createdAt": 6, "likes": 2 },
{ "owner": "A", "content": "First bark!", "createdAt": 1, "likes": 1 },
{ "owner": "A", "content": "Second bark", "createdAt": 3, "likes": 20 },
{ "owner": "C", "content": "Bark", "createdAt": 5, "likes": 1 }
After grouping them by one hour intervals:
In this example, 0-3599 seconds is one group and 3600-7199 seconds is another group.
{ "owner": "C", "content": "Bark Bark Bark", "createdAt": 3619, "likes": 0 },
{ "owner": "C", "content": "Bark Bark", "createdAt": 3615, "likes": 1 },
{ "owner": "B", "content": "Hello world", "createdAt": 3610, "likes": 3 }
{ "owner": "A", "content": "Third bark!", "createdAt": 6, "likes": 2 },
{ "owner": "A", "content": "First bark!", "createdAt": 1, "likes": 1 },
{ "owner": "A", "content": "Second bark", "createdAt": 3, "likes": 20 },
{ "owner": "C", "content": "Bark", "createdAt": 5, "likes": 1 }
Finally, after sorting within those groups and recombining them, the Home view displays the Barks to the user in descending order of "most likeable":
{ "owner": "B", "content": "Hello world", "createdAt": 3610, "likes": 3 },
{ "owner": "C", "content": "Bark Bark", "createdAt": 3615, "likes": 1 },
{ "owner": "C", "content": "Bark Bark Bark", "createdAt": 3619, "likes": 0 },
{ "owner": "A", "content": "Second bark", "createdAt": 3, "likes": 20 },
{ "owner": "A", "content": "Third bark!", "createdAt": 6, "likes": 2 },
{ "owner": "C", "content": "Bark", "createdAt": 5, "likes": 1 },
{ "owner": "A", "content": "First bark!", "createdAt": 1, "likes": 1 }
Both authed
and guest
users will see Barks sorted by likability, but guests
will see all Barks in the system regardless of who created them. Unless they
are not following anyone, authed
users will only see Barks from the users
they're directly following.
If an authed
user isn't following any other users yet, they should see the
same Barks a guest
would. When there are no more Barks to show an authed
user (i.e. they scrolled to the absolute bottom), they should also begin seeing
the same Barks a guest
would. No user will ever see an empty Home view
unless there is an error.
Pack view: create and interact with Barks from the most important users.
When an authed
user follows another user, they'll have the
choice to add that user to their Pack. This has the same effect as normally
following the user with one additional feature: Barks owned by users from the
Pack also appear in this separate view. Like the Home view,
the Pack view shows the user a list of Barks sorted in order of most likeable,
but this view will filter out any Barks with owners not in the Pack.
authed
users can also add and remove other users from their Pack without
leaving this view.
This is a private view unique to each user. guest
users cannot access this
view.
Bookmark view: view and manage Barks saved for later.
This view shows an authed
user the list of Barks they've bookmarked. Unlike
the other views that list Barks, this view will sort Barks by bookmarked
time in descending order. That is: the most recently bookmarked Barks will
appear first regardless of who owns them or when they were created. Further,
Barks in this view will have a second timestamp detailing when the Bark was
bookmarked.
Your app must record timing data (e.g. timestamp) when your user bookmarks a Bark. Later, if this timing data is not available for whatever reason, this should be reflected in the UI (e.g. a warning) and bookmarked Barks should be organized by creation date instead.
authed
users can also remove bookmarks without leaving this view.
This is a private view unique to each user. guest
users cannot access this
view.
Auth view: authed
user registration and login.
guest
users can use this view to login using their username or email and
their password. There is an open registration feature guests can use to
register a new account. When they do, they must provide the following where
required:
- Full name <required>
- Phone number
- Email address <required>
- Password <required>
- Password strength must be indicated as well. Weak passwords will be rejected. A weak password is ≤10 characters. A moderate password is 11-17 characters. A strong password is above 17 characters.
- The answer to a simple CAPTCHA challenge of some type <required>
- Example:
what is 2+2=?
- Teams must not call out to any API for this. Teams must create the CAPTCHA manually.
- Example:
Unlike past problem statements, user creation/deletion is managed for you through the API. However, dealing with login credentials and other custom user data is still your team's responsibility. Use of a local database is recommended.
authed
users can use this view to logout, though there should be an easier way
to logout than returning to this view.
Additional constraints:
- Guests will be prevented from logging in for 1 hour after 3 failed login attempts. Guests will always see how many attempts they have left.
- Guests will have the option to use remember me functionality to maintain long-running authentication state. That is: if guests login and want to be "remembered," they will not be logged out until they manually log out.
authed
users can mention other users in their Barks.
authed
users can "mention" other users by authoring a Bark containing an @
followed by the target user's username, e.g.
This is the bark @username mentioned
. If the user doesn't exist, it's just
text. If the user does exist, the text becomes a mention, which becomes a link
allowing other users to follow the mentioned user.
Barks that mention the user will appear in some form at the top of whatever view they appear in where they remain until dismissed by the user. It will be clearly communicated by the UI that the Bark is highlighted because of a mention. Mentions that have been dismissed will not reappear at the top of the view.
If a customer does not remember their password, they can use email to recover their account.
If a customer has forgotten their login credentials, they will be able to recover their account by clicking a link in the recovery email sent to their address.
The app must not actually send emails out onto the internet. The sending of emails can be simulated however you want, including outputting the would-be email to the console. The app will not use an external API or service for this. For full points, ensure you document how recovery emails are simulated when submitting your solution.
authed
users can follow other users.
authed
users can easily "follow" and "unfollow" other authed
users without
switching views. When a user follows another user, the followed user's Barks
appear in the follower user's Home view.
Users can also add other users to their Pack, which is a special type of "follow".
The app will suggest other authed
users to follow.
The app will suggest up to 5 other users to follow based on:
- The users who authored Barks the
authed
user liked - The users followed by a user the
authed
user follows (i.e. an "indirect follow")
For example, if:
- User A follows users B and C
- User B follows users E, F, G, H, M, N
- User C follows users D, E, I, J, K, and L
- User A liked 1 Bark from user E and 3 Barks from user I
Then the app would suggest user A follow these users in the following order:
- I (3 likes + 1 indirect follows)
- E (1 likes + 2 indirect follows)
- D (0 likes + 1 indirect follows)
- F (0 likes + 1 indirect follows)
- G (0 likes + 1 indirect follows)
If the user is not following anyone and has not liked any Barks, or has not liked/followed enough content to be recommended five users, they are shown five random users instead.
Counts displaying like/rebark/bark-back totals will update in the UI in real time; new Barks and bark-backs will appear as they happen.
Whenever a Bark's count data changes in the API, the new data will be reflected in the UI without the page refreshing or the user doing anything extra (like pressing a refresh button). This type of automatic updating is called asynchronous or "ajaxian" since it occurs outside the usual synchronous event flow.
Similarly, whenever a new Bark or bark-back is created, it will appear in the UI of every relevant user soon after. This will happen without forcing a page refresh.
Typically, asynchronous features are implemented using frontend timers.
Whenever a Bark's metadata changes (e.g.
likes
increases by 1), that means fresh data can be pulled from the API (e.g. using theGET /:bark_id/likes
endpoint to see the latest likes).
The app will be performant.
The amount of time the application takes to load and sort data, display information, and act on input is progressively penalized. That is: the teams with the fastest load times will earn the most points and the teams with the slowest load times will earn zero points from this requirement.
Average (median) is used to calculate load times. Measurements will include initial page load times and, depending on the other requirements, various other frontend UI response times.
Tail latencies (e.g. on startup with a cold cache) are ignored. Only averages are considered.
FOUC may also be penalized.
To maximize performance, consider caching (see also) the result of data processing operations and using range queries to retrieve only the data your app hasn't yet processed.
Results and lists of items displayed in the frontend UI will be paginated using infinite scrolling where appropriate.
Pagination is the strategy of showing a limited number of a large set of results and providing a navigation element where users can switch to different "pages" of that large set. Infinite scroll is a specific implementation of the pagination strategy. Facebook and Instagram's infinite scroll news feeds are good examples.
Security: no XSS, SQLI, insecure database, or other trivial security vulnerabilities.
The app will use modern software engineering practices that protect from common XSS, SQL injection, and other security vulnerabilities. Specifically: form inputs and the like will not be vulnerable to SQL injection attacks. User-generated outputs will not be vulnerable to XSS or similar attacks.
As for database security, any passwords present in the database must be hashed (not encrypted). We recommend using a salted SHA-256 hash construction or something similar. You don't need to do anything fancy. There are many tutorials for how to safely store passwords and other credentials in a database.
Passwords stored in your database in cleartext, hashed incorrectly, or re-encoded (e.g. with base64) will earn your team zero points for this requirement.
The app will fail gracefully when exceptional conditions are encountered.
This includes handling API errors during fetch, login errors, random exceptions, showing spinners when content needs to load, etc.
Every so often, the API will respond with an
HTTP 555
error instead of fulfilling a request. Further, API requests and responses will be manipulated by the judges in an attempt to break the app. If at any time a user is presented with a non-app error page or a completely blank screen for more than a second or so, your solution may lose points on this requirement.
The frontend UI will be responsive to mobile, tablet, and desktop viewports.
The app will be pleasant to the eye when viewed on a smartphone, tablet, and a desktop viewport. The design and functionality will not "break" across these viewports nor will the app become non-functional.
Judges will view and interact with the app through emulated phone and tablet viewports. If the app breaks when viewed, it will lose points on this and other requirements. We recommend using mobile-first software design principles.