This project is a full-stack application built with Node.js, TypeScript, Express, React, and Vite. It is designed to provide a robust and scalable backend service for handling various data operations and a modern frontend for interacting with the data. The application fetches data from a remote endpoint and transforms it to handle filtering and pagination. It also includes a caching system to optimize performance.
The application is structured into two main parts:
The server-side application is structured as follows:
-
Controllers: These handle incoming HTTP requests and send responses. See
IndexController
andDataController
. -
Services: These contain the business logic of the application. See
DataService
andCacheService
. -
Routes: These define the application's endpoints. See
IndexRoute
andDataRoute
. -
Middlewares: These handle error processing and other intermediate functions. See
errorMiddleware
. -
Models: These define the structure of the data. See
DataModel
andDataList
.
The client-side application is structured as follows:
-
Components: These are the building blocks of the UI.
-
Containers: These manage the state and logic of the paginated and filtered data table. See
PaginatedTableContainer
. -
Hooks: Custom hooks to encapsulate reusable logic. See
useFetch
.
The useFetch
hook is a custom hook designed to handle data fetching with support for loading and error states. It uses axiosInstance
to make HTTP requests and manages the request lifecycle, including cancellation on component unmount. This hook simplifies data fetching in components and ensures a consistent approach across the application.
To improve Cumulative Layout Shift (CLS) in the web application, several strategies have been implemented:
- Loading skeleton spinner: Placeholder skeleton spinner are used to provide a visual loading indication.
- Fixed Layouts: Explicit widths and heights are set for table cells to ensure a stable and predictable layout.
- Font Loading: The
font-display: swap
property is used to ensure that fallback fonts are displayed immediately, and custom fonts are swapped in once they are loaded. Additionally, fonts are preloaded to ensure they are loaded as quickly as possible.

In development mode, React Strict Mode is enabled, which intentionally double-invokes certain lifecycle methods and effects to help identify potential issues. This can result in components making two requests during development, but this behavior does not occur in production. You can try it on you own building and executing server and web with the following commands:
npm run start
npm run preview
- Node.js (v20 or higher)
- npm or yarn
-
Navigate to the
server
directory:cd server
-
Install dependencies:
npm install
-
Run the server in development mode (watches for any file changes):
npm run dev
-
The server will be running at http://localhost:3000/ or http://localhost:3000/data.
-
To build and run the server from the
dist
directory:npm run start
To run tests:
-
After dependencies are installed, run tests:
npm run test
-
Run tests watching for changes:
npm run test:watch
-
Navigate to the
web
directory:cd web
-
Install dependencies:
npm install
-
Run the web application in development mode:
npm run dev
-
The web application will be running at http://localhost:5173/.
-
To build the web application:
npm run build
-
To preview the built web application:
npm run preview
To run tests:
-
After dependencies are installed, run tests:
npm run test
-
Run tests with coverage:
npm run test:coverage
- The application uses TypeScript for type safety and better developer experience.
- Express is used for the backend to handle HTTP requests and responses.
- React is used for the frontend to build a dynamic and responsive user interface.
- Vite is used as the build tool for the frontend for faster development and build times.
- Axios is used for making HTTP requests from both the server and the client.
- A caching system is implemented on the server to optimize performance by reducing the number of requests to the remote endpoint.
- Using TypeScript adds a learning curve for developers not familiar with it, but it provides better type safety and code quality.
- Implementing a caching system adds complexity to the server-side code but significantly improves performance.
This project provides a robust and scalable solution for handling data operations with a modern frontend for interacting with the data. By following the instructions above, you can set up and run the application locally for development and testing purposes.