Read this README thoroughly!
This project was created using Node.js v22, and we assume that you will use it (it was created with v22.15.0). To run the project, you first need to install all dependencies:
npm install
Then, you can run the project with:
npm run frontend
and
npm run backend
- Clone this repository.
- Create a branch named using your name and the year and month, like
jaroslavhejlek202505
. - Switch to the branch and follow the
Getting Started
guide. - Read through the existing code and note any work that needs to be done (it's marked with TODO comments and also explained below).
- Start your timer and start working.
- Plan your work.
- Complete all the
TODO
comments marked asLVL1
. - When you are finished, stop the timer and record your time.
- Commit all your uncommitted changes with the commit message:
feat: level 1 done
. If you do not want to continue withLVL2
, create a pull request.- The title should be
<Your name> - <Date>
. - In the pull request description:
- Write how long it took you to finish
LVL1
and optionally how long you spent planning. - Add whether you got stuck anywhere and any other information that you feel is important and not clear from the code.
- Write how long it took you to finish
- The title should be
- Optional: If the
LVL1
TODOs were easy for you and you want to do more, you can continue with theLVL2
TODOs.- Once you are done, create the pull request as described in point 9, but also include how long it took you to complete
LVL2
.
- Once you are done, create the pull request as described in point 9, but also include how long it took you to complete
- The
TODO
comments marked asLVL1
are required. - The
TODO
comments marked asLVL2
are optional; do them only after you finish the first level, and you do not have to do all of them. - The code should be clean and readable.
- The code should pass all ESLint checks.
- The code should pass all tests, including the tests you create yourself. If you did not implement some functionality, remove the tests.
- You can only install one additional package, either by adding a new package or replacing a package you won't use. This is not a hint; it's a limit.
- It's allowed to use AI to help you complete this task. However, be prepared that if you succeed, we will ask you to explain parts of the code and potentially change them, so you must understand what the code does.
We do not want you to spend too much of your time on this task. It's completely fine if you finish just the first level. If you finish only the first level, we will probably ask you how you would solve the second-level task during later steps of the interview process. If you do finish them, we will just review your solution.
The tasks from the second level are there for two reasons:
- You found the first level too easy and want to challenge yourself.
- You are worried you would not work well under pressure during a personal interview and want to show more of your skills while safe at home. :)
We currently use StyledComponents
in Apify. However, in the future, we will probably switch to another styling system. If you do not like it, you can change it to another system before you start your timer, but please note it in the PR description.
Check the
example-lvl1.mp4
andexample-lvl2.mp4
first to see videos of example solutions. It will hopefully make reading through this description less confusing.
This task is very loosely based on the data from the Advent of Code 2023 Day 3 challenge, which you can find here if you are interested.
The main goal of this task is to create an app that will visualize data very similar to the data from the challenge.
- The frontend uses a mock
matrix
string in theuseMatrix
hook. - The backend endpoint does nothing.
- The frontend does two things:
- Renders the matrix itself as pure HTML:
.
is rendered as an empty cell.- The symbols are rendered from the
frontend/src/assets
folder using thesymbolToIcon
helper object. - Numbers are left untouched.
- Renders buttons for each neighborhood, where neighborhoods are cells around a symbol, including the symbol:
- The button contains only the icon of the symbol.
- The buttons are disabled.
- Renders the matrix itself as pure HTML:
- There are disabled buttons missing interactivity in the header of the page, indicating filters for each type of neighborhood.
- There is a performance indicator that changes colors if the browser processing thread is blocked for too long.
- The backend endpoint generates an 80x80 2D matrix.
- Please see the
example.mp4
file to see how the final matrix looks when rendered. - The matrix has three types of values:
.
indicates empty space.1
,2
,3
,4
,5
,6
,7
,8
,9
are numbers that count towards the value of the neighborhood.#
,@
,$
,%
,&
,*
are symbols that indicate the type of neighborhood.
- There should be 30% of cells empty, and from the remaining 70% of cells, 90% should be numbers, and the rest symbols.
- The matrix is returned to the client as a string in a JSON object
{ matrix: '<matrix>' }
with lines delimited by\n
and cells delimited by spaces. - Implement a unit test on the backend that tests if the ratios of the generated cells are correct.
- Please see the
- Style the frontend in any way you want.
- The frontend loads data from the
GET /
endpoint of the backend usingreact-query
. - The neighborhood buttons should, in addition to the icon, also display the value of the neighborhood:
- The value of the neighborhood is the sum of the numbers in the neighborhood (around the symbol).
- When you click on the neighborhood button, it should visually highlight the neighborhood in the matrix.
- How it's highlighted visually is up to you.
- Implement a Cypress test that tests that the neighborhood in the matrix is highlighted after its button is pressed.
- When generating the matrix on the backend, ensure that two neighborhoods never cross.
- This means that cells from one neighborhood cannot be cells of another neighborhood.
- Write a test for this functionality.
- Add an option to cache the generated matrix. For this, you need to implement three things:
- Use a seedable random number generator when creating the matrix (check
backend/lib/random
). - Cache the generated matrix in the app controller or in the service.
- Add tests for this functionality. If you cache it in the controller, create tests for the controller.
- Use a seedable random number generator when creating the matrix (check
- Add an option to highlight a specific type of neighborhood in the matrix and add tests for it.
- Add an option to display borders of the active neighborhood. This adds additional complexity on top of the highlighting from Level 1.
Good luck! :)
Both the frontend and backend have tests and ESLint. To run ESLint on the whole project, you can run:
npm run lint
To test the whole project, you can run:
npm run test
For the frontend tests to run properly, the frontend of the project needs to be running, but the backend does not have to.
The commands above use concurrently
to run the commands on both the frontend and backend. If you want to run them separately, you can use :backend
or :frontend
to run them on only one service.
So the commands for the frontend are npm run lint:frontend
and npm run test:frontend
. The same can be done for the backend.
There are additional commands available inside the specific folders. Check the ./frontend/package.json
and ./backend/package.json
to see what is available there.