This repository contains a full-stack application for displaying activities and suppliers data. It is composed of a React frontend, a Node.js backend, and a Cypress end-to-end testing suite.
Made by Felipe Silva (https://github.com/felipesilvati)
- frontend: A Vite + React application that fetches and renders activities and suppliers data from the backend.
- backend: A Node.js Express application that serves as an API provider for activities and suppliers information.
- e2e: A Cypress end-to-end testing suite that ensures the application's features work as expected with significant test coverage.
To run the application:
-
Ensure that Docker is installed on your system.
-
Clone the repository to your local machine.
-
Navigate to the root directory of the project.
-
Run the following command to build and start all services:
docker compose up --build # or simply ./run.sh
This command will start the frontend application and the backend API. Once the services are running, you can access:
- The frontend at
http://localhost:4173
. - The backend API endpoints directly at
http://localhost:3001
.
To execute the end-to-end tests:
./run-e2e-tests.sh
This will open the backend, frontend and the Cypress Test Runner in the terminal.
You can also run it locally with the following steps:
-
Make sure that both frontend/backend services are running.
-
Navigate to the
/e2e
directory. -
Run the following command to start the Cypress Test Runner:
yarn install yarn run cypress open
To run the frontend unit tests:
-
Navigate to the
/frontend
directory. -
Run the following command to execute the tests:
yarn install yarn test
To run the backend unit tests:
-
Navigate to the
/backend
directory. -
Run the following command to execute the tests:
yarn install yarn test
When approaching the GetYourGuide Tech Challenge, I made strategic decisions to craft a solution that balances rapid development with best practices in software architecture.
The frontend is powered by Vite and React, a combination chosen for its exceptional development speed and robust build optimizations, especially beneficial for a project with a tight deadline. Vite's out-of-the-box features, such as fast refresh and efficient bundling, allowed me to quickly see changes and iterate on the application's functionality.
React's component-based model was instrumental in building a modular and maintainable codebase. The use of Storybook paralleled this approach, offering a sandbox to develop and test UI components in isolation. This not only expedited the frontend development process but also ensured a high fidelity in the visual rendering of components, which is crucial for a user-centric application.
For the backend, I implemented a Node.js application with an Express server, a choice driven by its simplicity and flexibility. This setup enabled me to quickly scaffold a RESTful API that could reliably serve data from the provided activities.json
and suppliers.json
files. Although frameworks like NestJS offer extensive standardization, Express's minimalist nature was more in line with the project's scope, allowing for an agile development process without the overhead of a more opinionated framework.
A key feature of the backend is pagination, ensuring the API remains scalable and performant regardless of the dataset's size. This design decision anticipates future growth and addresses potential performance bottlenecks by limiting the number of activities delivered in a single response, thereby optimizing data transfer and load times.
Testing was a cornerstone of the development cycle. I leveraged Jest for unit testing to validate both backend and frontend components, ensuring reliability at the module level. To guarantee the integrated application functions as intended, I introduced an end-to-end testing suite using Cypress. This was particularly crucial for validating the application's behavior in a Dockerized environment, simulating real-world usage scenarios.
The decision to use a REST API over GraphQL was deliberate, aimed at maintaining simplicity and reducing the initial setup complexity. Given the current requirements, REST provided a straightforward, time-efficient solution without sacrificing the application's quality or future scalability.
In summary, the design choices made throughout this project were carefully considered to align with the challenge's objectives—delivering a scalable, testable, and high-quality application within a defined timeframe. These choices reflect a strategic approach to software development that prioritizes adaptability, performance, and maintainability.
- Init Express Backend with a REST API (healthcheck)
- Endpoint to get list of activities
- Endpoint to get suppliers
- Endpoint to get activities with suppliers combined
- Decide on REST vs. GraphQL for API
- Add pagination for the list of activities
- Add a Dockerfile for the backend
- Init React Frontend
- Create a storybook for the main UI components
- Create UI showing list of activities
- Add a search bar to filter activities (ensure alignment with backend filtering logic decision)
- Add a Dockerfile for the frontend
- Ensure client application consumes the API exposed by the backend (activities)
- Ensure client application consumes the API exposed by the backend (suppliers)
- Ensure client application consumes the API exposed by the backend (activities with suppliers combined)
- Ensure pagination works as expected with the client application
- Ensure the project can be run locally with the provided Docker compose file (
docker-compose up --build
) - Modify/add any dependencies as required for Docker integration
- Document architectural decisions and rationale
- Note any features/improvements left out due to time constraints
- List any assumptions made during development
- Prepare documentation for setup and API usage in
readme.md
- Check unit test coverage for both backend and frontend components
- Ensure functionality works as expected with Docker setup
- End to end testing for the application
- Prepare project for submission (exclude
node_modules
or other dependency directories) - Be prepared to present the work, demo the application, and explain architectural choices and code
- Ready for live coding during the interview to refactor code, add features, or fix bugs
- Replace json files with a SQL database
- Use opinionated framework for the backend (e.g., NestJS) to improve scalability and maintainability
- Authentication and Authorization for the API
- Add more advanced error handling and logging
- Implement UI to display more activity details by ID (redundant for now)
- Replace the current search bar with more advanced search features (e.g., sorting, filtering, etc.)
- Add caching mechanism (based on performance needs)
- Fix variable ActivityCard component height for better UI/UX
- "Hot reload" frontend/backend container and skip build caching to not get stuck with old content